Subversion Repositories Kolibri OS

Rev

Rev 6107 | Rev 6273 | 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: 6151 $
  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     ecx, [ebp+NTFS.ntfs_attr_offs]
  446.         cmp     byte [ecx+nonResidentFlag], 1
  447.         jnz     .failFreeBitmapMFT
  448.         mov     [ebp+NTFS.mftBitmapSize], eax
  449.         mov     eax, [ebp+NTFS.ntfsLastRead]
  450.         mov     [ebp+NTFS.mftBitmapLocation], eax
  451.  
  452.         mov     eax, ebp
  453. .pop_exit:
  454.         pop     esi ebp ebx
  455. .exit:
  456.         cmp     dword [esp+4], 0
  457.         jz      @f
  458.         sub     ebx, 512
  459. @@:
  460.         ret
  461.  
  462. .failFreeBitmapMFT:
  463.         stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
  464. .failFreeBitmap:
  465.         stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
  466. .failFreeIndex:
  467.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  468. .fail_free_mft:
  469.         stdcall kernel_free, [ebp+NTFS.mft_retrieval]
  470. .fail_free_frs:
  471.         stdcall kernel_free, [ebp+NTFS.frs_buffer]
  472. .fail_free:
  473.         mov     eax, ebp
  474.         call    free
  475.         xor     eax, eax
  476.         jmp     .pop_exit
  477.  
  478. .get_mft_retrieval_ptr:
  479.         pushad
  480.         mov     eax, [ebp+NTFS.mft_retrieval_size]
  481.         cmp     eax, [ebp+NTFS.mft_retrieval_alloc]
  482.         jnz     .ok
  483.         add     eax, 0x1000/8
  484.         mov     [ebp+NTFS.mft_retrieval_alloc], eax
  485.         shl     eax, 3
  486.         stdcall kernel_alloc, eax
  487.         test    eax, eax
  488.         jnz     @f
  489.         popad
  490.         add     esp, 14h
  491.         jmp     .fail_free_mft
  492. @@:
  493.         mov     esi, [ebp+NTFS.mft_retrieval]
  494.         mov     edi, eax
  495.         mov     ecx, [ebp+NTFS.mft_retrieval_size]
  496.         add     ecx, ecx
  497.         rep movsd
  498.         push    [ebp+NTFS.mft_retrieval]
  499.         mov     [ebp+NTFS.mft_retrieval], eax
  500.         call    kernel_free
  501.         mov     eax, [ebp+NTFS.mft_retrieval_size]
  502. .ok:
  503.         shl     eax, 3
  504.         add     eax, [ebp+NTFS.mft_retrieval]
  505.         mov     [esp+28], eax
  506.         popad
  507.         ret
  508.  
  509. ntfs_free:
  510.         push    ebx
  511.         mov     ebx, eax
  512.         stdcall kernel_free, [ebx+NTFS.frs_buffer]
  513.         stdcall kernel_free, [ebx+NTFS.mft_retrieval]
  514.         stdcall kernel_free, [ebx+NTFS.cur_index_buf]
  515.         stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
  516.         stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
  517.         mov     eax, ebx
  518.         pop     ebx
  519.         jmp     free
  520.  
  521. ntfs_lock:
  522.         lea     ecx, [ebp+NTFS.Lock]
  523.         jmp     mutex_lock
  524.  
  525. ntfs_unlock:
  526.         lea     ecx, [ebp+NTFS.Lock]
  527.         jmp     mutex_unlock
  528.  
  529. ntfs_read_frs_sector:
  530.         push    ecx
  531.         mov     ebx, [ebp+NTFS.frs_buffer]
  532.         push    ebx
  533.         mov     ecx, [ebp+NTFS.frs_size]
  534.         shr     ecx, 9
  535.         push    ecx
  536.         mov     ecx, eax
  537. @@:
  538.         mov     eax, ecx
  539.         call    fs_read32_sys
  540.         test    eax, eax
  541.         jnz     .fail
  542.         add     ebx, 0x200
  543.         inc     ecx
  544.         dec     dword [esp]
  545.         jnz     @b
  546.         pop     eax
  547. .fail:
  548.         pop     ebx
  549.         pop     ecx
  550.         ret
  551.  
  552. ntfs_read_attr:
  553. ; [ebp+NTFS.ntfsWriteAttr]=1 -> write attribute
  554. ;   in:
  555. ; [ebp+NTFS.ntfs_cur_iRecord] = number of fileRecord
  556. ; [ebp+NTFS.ntfs_cur_attr] = attribute type
  557. ; [ebp+NTFS.ntfs_cur_offs] = attribute VCN in sectors
  558. ; [ebp+NTFS.ntfs_cur_buf] -> buffer for data
  559. ; [ebp+NTFS.ntfs_cur_size] = max sectors to read
  560. ;   out:
  561. ; [ebp+NTFS.ntfs_cur_read] = bytes readen
  562. ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
  563.         xor     eax, eax
  564.         pushad
  565.         and     [ebp+NTFS.ntfs_cur_read], 0
  566.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  567.         jnz     .nomft
  568.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x80
  569.         jnz     .nomft
  570.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  571.         inc     eax
  572.         mul     [ebp+NTFS.sectors_per_cluster]
  573.         cmp     eax, [ebp+NTFS.ntfs_cur_offs]
  574.         jbe     .nomft
  575. ; precalculated part of $Mft $DATA
  576.         mov     esi, [ebp+NTFS.mft_retrieval]
  577.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  578.         xor     edx, edx
  579.         div     [ebp+NTFS.sectors_per_cluster]
  580. ; eax = VCN, edx = offset in sectors from beginning of cluster
  581.         xor     ecx, ecx        ; ecx will contain LCN
  582. .mftscan:
  583.         add     ecx, [esi+4]
  584.         sub     eax, [esi]
  585.         jb      @f
  586.         add     esi, 8
  587.         push    eax
  588.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  589.         shl     eax, 3
  590.         add     eax, [ebp+NTFS.mft_retrieval]
  591.         cmp     eax, esi
  592.         pop     eax
  593.         jnz     .mftscan
  594.         jmp     .nomft
  595. @@:
  596.         push    ecx
  597.         add     ecx, eax
  598.         add     ecx, [esi]
  599.         push    eax
  600.         push    edx
  601.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  602.         mul     ecx
  603. ; eax = sector on partition
  604.         pop     edx
  605.         add     eax, edx
  606.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  607.         pop     ecx
  608.         neg     ecx
  609.         imul    ecx, [ebp+NTFS.sectors_per_cluster]
  610.         sub     ecx, edx
  611.         mov     [ebp+NTFS.ntfsLastRead], eax
  612.         cmp     ecx, [ebp+NTFS.ntfs_cur_size]
  613.         jb      @f
  614.         mov     ecx, [ebp+NTFS.ntfs_cur_size]
  615. @@:
  616. ; ecx = number of sequential sectors to read
  617.         push    eax
  618.         call    fs_read32_sys
  619.         pop     edx
  620.         test    eax, eax
  621.         jnz     .errread
  622.         add     [ebp+NTFS.ntfs_cur_read], 0x200
  623.         dec     [ebp+NTFS.ntfs_cur_size]
  624.         inc     [ebp+NTFS.ntfs_cur_offs]
  625.         add     ebx, 0x200
  626.         mov     [ebp+NTFS.ntfs_cur_buf], ebx
  627.         lea     eax, [edx+1]
  628.         loop    @b
  629.         pop     ecx
  630.         xor     eax, eax
  631.         xor     edx, edx
  632.         cmp     [ebp+NTFS.ntfs_cur_size], eax
  633.         jz      @f
  634.         add     esi, 8
  635.         push    eax
  636.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  637.         shl     eax, 3
  638.         add     eax, [ebp+NTFS.mft_retrieval]
  639.         cmp     eax, esi
  640.         pop     eax
  641.         jz      .nomft
  642.         jmp     .mftscan
  643. @@:
  644.         popad
  645.         ret
  646. .errread:
  647.         pop     ecx
  648. .errret:
  649.         mov     [esp+28], eax
  650.         stc
  651.         popad
  652.         ret
  653. .nomft:
  654. ; 1. Read file record.
  655. ; N.B. This will do recursive call of read_attr for $MFT::$Data.
  656.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  657.         mov     [ebp+NTFS.ntfs_attr_iRecord], eax
  658.         and     [ebp+NTFS.ntfs_attr_list], 0
  659.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  660.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  661.         or      [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  662.         call    ntfs_read_file_record
  663.         jc      .errret
  664. ; 2. Find required attribute.
  665.         mov     eax, [ebp+NTFS.frs_buffer]
  666. ; a) For auxiliary records, read base record.
  667. ; If base record is present, base iRecord may be 0 (for $Mft),
  668. ; but SequenceNumber is nonzero.
  669.         cmp     dword [eax+24h], 0
  670.         jz      @f
  671.         mov     eax, [eax+20h]
  672. .beginfindattr:
  673.         mov     [ebp+NTFS.ntfs_attr_iRecord], eax
  674.         call    ntfs_read_file_record
  675.         jc      .errret
  676.         jmp     @f
  677. .newAttribute:
  678.         pushad
  679. @@:
  680. ; b) Scan for required attribute and for $ATTR_LIST
  681.         mov     eax, [ebp+NTFS.frs_buffer]
  682.         movzx   ecx, word [eax+14h]
  683.         add     eax, ecx
  684.         mov     ecx, [ebp+NTFS.ntfs_cur_attr]
  685.         and     [ebp+NTFS.ntfs_attr_offs], 0
  686. .scanattr:
  687.         cmp     dword [eax], -1
  688.         jz      .scandone
  689.         cmp     dword [eax], ecx
  690.         jz      .okattr
  691.         cmp     [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  692.         jnz     .scancont
  693.         cmp     dword [eax], 0x20       ; $ATTR_LIST
  694.         jnz     .scancont
  695.         mov     [ebp+NTFS.ntfs_attr_list], eax
  696.         jmp     .scancont
  697. .okattr:
  698. ; ignore named $DATA attributes (aka NTFS streams)
  699.         cmp     ecx, 0x80
  700.         jnz     @f
  701.         cmp     byte [eax+9], 0
  702.         jnz     .scancont
  703. @@:
  704.         mov     [ebp+NTFS.ntfs_attr_offs], eax
  705. .scancont:
  706.         add     eax, [eax+4]
  707.         jmp     .scanattr
  708. .continue:
  709.         pushad
  710.         and     [ebp+NTFS.ntfs_cur_read], 0
  711. .scandone:
  712. ; c) Check for required offset and length
  713.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  714.         jecxz   .noattr
  715.         push    [ebp+NTFS.ntfs_cur_size]
  716.         push    [ebp+NTFS.ntfs_cur_read]
  717.         call    .doreadattr
  718.         pop     edx
  719.         pop     ecx
  720.         jc      @f
  721.         cmp     [ebp+NTFS.ntfs_bCanContinue], 0
  722.         jz      @f
  723.         sub     edx, [ebp+NTFS.ntfs_cur_read]
  724.         neg     edx
  725.         shr     edx, 9
  726.         sub     ecx, edx
  727.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  728.         jnz     .not_in_cur
  729. @@:
  730.         popad
  731.         ret
  732. .noattr:
  733. .not_in_cur:
  734.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x20
  735.         jz      @f
  736.         mov     ecx, [ebp+NTFS.ntfs_attr_list]
  737.         test    ecx, ecx
  738.         jnz     .lookattr
  739. .ret_is_attr:
  740.         and     dword [esp+28], 0
  741.         cmp     [ebp+NTFS.ntfs_attr_offs], 1     ; CF set <=> ntfs_attr_offs == 0
  742.         popad
  743.         ret
  744. .lookattr:
  745. ; required attribute or required offset was not found in base record;
  746. ; it may be present in auxiliary records;
  747. ; scan $ATTR_LIST
  748.         mov     eax, [ebp+NTFS.ntfs_attr_iBaseRecord]
  749.         cmp     eax, -1
  750.         jz      @f
  751.         call    ntfs_read_file_record
  752.         jc      .errret
  753.         or      [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  754. @@:
  755.         push    [ebp+NTFS.ntfs_cur_offs]
  756.         push    [ebp+NTFS.ntfs_cur_size]
  757.         push    [ebp+NTFS.ntfs_cur_read]
  758.         push    [ebp+NTFS.ntfs_cur_buf]
  759.         push    dword [ebp+NTFS.ntfs_attr_size]
  760.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  761.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  762.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  763.         and     [ebp+NTFS.ntfs_cur_offs], 0
  764.         mov     [ebp+NTFS.ntfs_cur_size], 2
  765.         and     [ebp+NTFS.ntfs_cur_read], 0
  766.         lea     eax, [ebp+NTFS.ntfs_attrlist_buf]
  767.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  768.         jnz     @f
  769.         lea     eax, [ebp+NTFS.ntfs_attrlist_mft_buf]
  770. @@:
  771.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  772.         push    eax
  773.         call    .doreadattr
  774.         pop     esi
  775.         mov     edx, 1
  776.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  777.         pop     dword [ebp+NTFS.ntfs_attr_size]
  778.         mov     ecx, [ebp+NTFS.ntfs_cur_read]
  779.         pop     [ebp+NTFS.ntfs_cur_buf]
  780.         pop     [ebp+NTFS.ntfs_cur_read]
  781.         pop     [ebp+NTFS.ntfs_cur_size]
  782.         pop     [ebp+NTFS.ntfs_cur_offs]
  783.         jc      .errret
  784.         or      edi, -1
  785.         lea     ecx, [ecx+esi-1Ah]
  786. .scanliststart:
  787.         push    ecx
  788.         mov     eax, [ebp+NTFS.ntfs_cur_attr]
  789. .scanlist:
  790.         cmp     esi, [esp]
  791.         jae     .scanlistdone
  792.         cmp     eax, [esi]
  793.         jz      @f
  794. .scanlistcont:
  795.         movzx   ecx, word [esi+4]
  796.         add     esi, ecx
  797.         jmp     .scanlist
  798. @@:
  799. ; ignore named $DATA attributes (aka NTFS streams)
  800.         cmp     eax, 0x80
  801.         jnz     @f
  802.         cmp     byte [esi+6], 0
  803.         jnz     .scanlistcont
  804. @@:
  805.         push    eax
  806.         mov     eax, [esi+8]
  807.         test    eax, eax
  808.         jnz     .testf
  809.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  810.         and     eax, dword [ebp+NTFS.ntfs_attr_size+4]
  811.         cmp     eax, -1
  812.         jnz     .testfz
  813. ; if attribute is in auxiliary records, its size is defined only in first
  814.         mov     eax, [esi+10h]
  815.         call    ntfs_read_file_record
  816.         jnc     @f
  817. .errret_pop:
  818.         pop     ecx ecx
  819.         jmp     .errret
  820. .errret2_pop:
  821.         xor     eax, eax
  822.         jmp     .errret_pop
  823. @@:
  824.         mov     eax, [ebp+NTFS.frs_buffer]
  825.         movzx   ecx, word [eax+14h]
  826.         add     eax, ecx
  827.         mov     ecx, [ebp+NTFS.ntfs_cur_attr]
  828. @@:
  829.         cmp     dword [eax], -1
  830.         jz      .errret2_pop
  831.         cmp     dword [eax], ecx
  832.         jz      @f
  833. .l1:
  834.         add     eax, [eax+4]
  835.         jmp     @b
  836. @@:
  837.         cmp     eax, 0x80
  838.         jnz     @f
  839.         cmp     byte [eax+9], 0
  840.         jnz     .l1
  841. @@:
  842.         cmp     byte [eax+8], 0
  843.         jnz     .sdnores
  844.         mov     eax, [eax+10h]
  845.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  846.         and     dword [ebp+NTFS.ntfs_attr_size+4], 0
  847.         jmp     .testfz
  848. .sdnores:
  849.         mov     ecx, [eax+30h]
  850.         mov     dword [ebp+NTFS.ntfs_attr_size], ecx
  851.         mov     ecx, [eax+34h]
  852.         mov     dword [ebp+NTFS.ntfs_attr_size+4], ecx
  853. .testfz:
  854.         xor     eax, eax
  855. .testf:
  856.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  857.         cmp     eax, [ebp+NTFS.ntfs_cur_offs]
  858.         pop     eax
  859.         ja      @f
  860.         mov     edi, [esi+10h]  ; keep previous iRecord
  861.         jmp     .scanlistcont
  862. @@:
  863.         pop     ecx
  864. .scanlistfound:
  865.         cmp     edi, -1
  866.         jnz     @f
  867.         popad
  868.         ret
  869. @@:
  870.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  871.         mov     [ebp+NTFS.ntfs_attr_iBaseRecord], eax
  872.         mov     eax, edi
  873.         jmp     .beginfindattr
  874. .scanlistdone:
  875.         pop     ecx
  876.         sub     ecx, ebp
  877.         sub     ecx, NTFS.ntfs_attrlist_buf-1Ah
  878.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  879.         jnz     @f
  880.         sub     ecx, NTFS.ntfs_attrlist_mft_buf-NTFS.ntfs_attrlist_buf
  881. @@:
  882.         cmp     ecx, 0x400
  883.         jnz     .scanlistfound
  884.         inc     edx
  885.         push    esi edi
  886.         lea     esi, [ebp+NTFS.ntfs_attrlist_buf+0x200]
  887.         lea     edi, [ebp+NTFS.ntfs_attrlist_buf]
  888.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  889.         jnz     @f
  890.         lea     esi, [ebp+NTFS.ntfs_attrlist_mft_buf+0x200]
  891.         lea     edi, [ebp+NTFS.ntfs_attrlist_mft_buf]
  892. @@:
  893.         mov     ecx, 0x200/4
  894.         rep movsd
  895.         mov     eax, edi
  896.         pop     edi esi
  897.         sub     esi, 0x200
  898.         push    [ebp+NTFS.ntfs_cur_offs]
  899.         push    [ebp+NTFS.ntfs_cur_size]
  900.         push    [ebp+NTFS.ntfs_cur_read]
  901.         push    [ebp+NTFS.ntfs_cur_buf]
  902.         push    dword [ebp+NTFS.ntfs_attr_size]
  903.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  904.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  905.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  906.         mov     [ebp+NTFS.ntfs_cur_offs], edx
  907.         mov     [ebp+NTFS.ntfs_cur_size], 1
  908.         and     [ebp+NTFS.ntfs_cur_read], 0
  909.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  910.         mov     ecx, [ebp+NTFS.ntfs_attr_list]
  911.         push    esi edx edi
  912.         call    .doreadattr
  913.         pop     edi edx esi
  914.         mov     ecx, [ebp+NTFS.ntfs_cur_read]
  915.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  916.         pop     dword [ebp+NTFS.ntfs_attr_size]
  917.         pop     [ebp+NTFS.ntfs_cur_buf]
  918.         pop     [ebp+NTFS.ntfs_cur_read]
  919.         pop     [ebp+NTFS.ntfs_cur_size]
  920.         pop     [ebp+NTFS.ntfs_cur_offs]
  921.         jc      .errret
  922.         lea     ecx, [ecx+ebp+NTFS.ntfs_attrlist_buf+0x200-0x1A]
  923.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  924.         jnz     .scanliststart
  925.         add     ecx, NTFS.ntfs_attrlist_mft_buf-NTFS.ntfs_attrlist_buf
  926.         jmp     .scanliststart
  927.  
  928. .doreadattr:
  929.         mov     [ebp+NTFS.ntfs_bCanContinue], 0
  930.         cmp     byte [ecx+8], 0
  931.         jnz     .nonresident
  932.         mov     eax, [ecx+10h]  ; length
  933.         mov     esi, eax
  934.         mov     edx, [ebp+NTFS.ntfs_cur_offs]
  935.         shr     eax, 9
  936.         cmp     eax, edx
  937.         jb      .okret
  938.         shl     edx, 9
  939.         sub     esi, edx
  940.         movzx   eax, word [ecx+14h]
  941.         add     edx, eax
  942.         add     edx, ecx        ; edx -> data
  943.         mov     eax, [ebp+NTFS.ntfs_cur_size]
  944.         cmp     eax, (0xFFFFFFFF shr 9)+1
  945.         jbe     @f
  946.         mov     eax, (0xFFFFFFFF shr 9)+1
  947. @@:
  948.         shl     eax, 9
  949.         cmp     eax, esi
  950.         jbe     @f
  951.         mov     eax, esi
  952. @@:
  953. ; eax = length, edx -> data
  954.         mov     [ebp+NTFS.ntfs_cur_read], eax
  955.         mov     ecx, eax
  956.         mov     eax, edx
  957.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  958.         call    memmove
  959.         and     [ebp+NTFS.ntfs_cur_size], 0      ; CF=0
  960.         ret
  961. .nonresident:
  962. ; Not all auxiliary records contain correct FileSize info
  963.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  964.         mov     edx, dword [ebp+NTFS.ntfs_attr_size+4]
  965.         push    eax
  966.         and     eax, edx
  967.         cmp     eax, -1
  968.         pop     eax
  969.         jnz     @f
  970.         mov     eax, [ecx+30h]  ; FileSize
  971.         mov     edx, [ecx+34h]
  972.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  973.         mov     dword [ebp+NTFS.ntfs_attr_size+4], edx
  974. @@:
  975.         add     eax, 0x1FF
  976.         adc     edx, 0
  977.         shrd    eax, edx, 9
  978.         sub     eax, [ebp+NTFS.ntfs_cur_offs]
  979.         ja      @f
  980. ; return with nothing read
  981.         and     [ebp+NTFS.ntfs_cur_size], 0
  982. .okret:
  983.         clc
  984.         ret
  985. @@:
  986. ; reduce read length
  987.         and     [ebp+NTFS.ntfs_cur_tail], 0
  988.         cmp     [ebp+NTFS.ntfs_cur_size], eax
  989.         jb      @f
  990.         mov     [ebp+NTFS.ntfs_cur_size], eax
  991.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  992.         and     eax, 0x1FF
  993.         mov     [ebp+NTFS.ntfs_cur_tail], eax
  994. @@:
  995.         cmp     [ebp+NTFS.ntfs_cur_size], 0
  996.         jz      .okret
  997.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  998.         xor     edx, edx
  999.         div     [ebp+NTFS.sectors_per_cluster]
  1000.         sub     eax, [ecx+10h]  ; first_vbo
  1001.         jb      .okret
  1002. ; eax = cluster, edx = starting sector
  1003.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x80
  1004.         jnz     .sys
  1005.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  1006.         jz      .sys
  1007.         push    fs_read64_app
  1008.         cmp     [ebp+NTFS.ntfsWriteAttr], 1
  1009.         jnz     @f
  1010.         mov     dword[esp], fs_write64_app
  1011.         jmp     @f
  1012. .sys:
  1013.         push    fs_read64_sys
  1014. @@:
  1015.         sub     esp, 10h
  1016.         movzx   esi, word [ecx+20h]     ; mcb_info_ofs
  1017.         add     esi, ecx
  1018.         xor     edi, edi
  1019.         mov     [ebp+NTFS.ntfsFragmentCount], 0
  1020. .readloop:
  1021.         call    ntfs_decode_mcb_entry
  1022.         jnc     .break
  1023.         add     edi, [esp+8]
  1024.         sub     eax, [esp]
  1025.         jae     .readloop
  1026.         push    ecx
  1027.         push    eax
  1028.         add     eax, [esp+8]
  1029.         add     eax, edi
  1030.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  1031.         add     eax, edx
  1032.         pop     ecx
  1033.         neg     ecx
  1034.         imul    ecx, [ebp+NTFS.sectors_per_cluster]
  1035.         sub     ecx, edx
  1036.         cmp     ecx, [ebp+NTFS.ntfs_cur_size]
  1037.         jb      @f
  1038.         mov     ecx, [ebp+NTFS.ntfs_cur_size]
  1039. @@:
  1040.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  1041.         mov     [ebp+NTFS.ntfsLastRead], eax
  1042.         push    ecx
  1043.         xor     edx, edx
  1044.         call    dword[esp+18h]
  1045.         pop     ecx
  1046.         test    eax, eax
  1047.         jnz     .errread2
  1048.         sub     [ebp+NTFS.ntfs_cur_size], ecx
  1049.         add     [ebp+NTFS.ntfs_cur_offs], ecx
  1050.         shl     ecx, 9
  1051.         add     [ebp+NTFS.ntfs_cur_read], ecx
  1052.         add     [ebp+NTFS.ntfs_cur_buf], ecx
  1053.         inc     [ebp+NTFS.ntfsFragmentCount]
  1054.         pop     ecx
  1055.         xor     eax, eax
  1056.         xor     edx, edx
  1057.         cmp     [ebp+NTFS.ntfs_cur_size], 0
  1058.         jnz     .readloop
  1059.         add     esp, 14h
  1060.         mov     eax, [ebp+NTFS.ntfs_cur_tail]
  1061.         test    eax, eax
  1062.         jz      @f
  1063.         sub     eax, 0x200
  1064.         add     [ebp+NTFS.ntfs_cur_read], eax
  1065. @@:
  1066.         clc
  1067.         ret
  1068. .errread2:
  1069.         pop     ecx
  1070.         add     esp, 14h
  1071.         stc
  1072.         ret
  1073. .break:
  1074.         add     esp, 14h        ; CF=0
  1075.         mov     [ebp+NTFS.ntfs_bCanContinue], 1
  1076.         ret
  1077.  
  1078. ntfs_read_file_record:
  1079. ; in: eax = iRecord
  1080. ; out: [ebp+NTFS.frs_buffer] -> file record
  1081. ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
  1082.     ; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
  1083.         push    ecx edx
  1084.         mov     ecx, [ebp+NTFS.frs_size]
  1085.         mul     ecx
  1086.         shrd    eax, edx, 9
  1087.         shr     edx, 9
  1088.         jnz     .errret
  1089.         push    [ebp+NTFS.ntfs_attr_iRecord]
  1090.         push    [ebp+NTFS.ntfs_attr_iBaseRecord]
  1091.         push    [ebp+NTFS.ntfs_attr_offs]
  1092.         push    [ebp+NTFS.ntfs_attr_list]
  1093.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  1094.         push    dword [ebp+NTFS.ntfs_attr_size]
  1095.         push    [ebp+NTFS.ntfs_cur_iRecord]
  1096.         push    [ebp+NTFS.ntfs_cur_attr]
  1097.         push    [ebp+NTFS.ntfs_cur_offs]
  1098.         push    [ebp+NTFS.ntfs_cur_size]
  1099.         push    [ebp+NTFS.ntfs_cur_buf]
  1100.         push    [ebp+NTFS.ntfs_cur_read]
  1101.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80   ; $DATA
  1102.         and     [ebp+NTFS.ntfs_cur_iRecord], 0   ; $Mft
  1103.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1104.         shr     ecx, 9
  1105.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  1106.         mov     eax, [ebp+NTFS.frs_buffer]
  1107.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1108.         call    ntfs_read_attr
  1109.         mov     edx, [ebp+NTFS.ntfs_cur_read]
  1110.         pop     [ebp+NTFS.ntfs_cur_read]
  1111.         pop     [ebp+NTFS.ntfs_cur_buf]
  1112.         pop     [ebp+NTFS.ntfs_cur_size]
  1113.         pop     [ebp+NTFS.ntfs_cur_offs]
  1114.         pop     [ebp+NTFS.ntfs_cur_attr]
  1115.         pop     [ebp+NTFS.ntfs_cur_iRecord]
  1116.         pop     dword [ebp+NTFS.ntfs_attr_size]
  1117.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  1118.         pop     [ebp+NTFS.ntfs_attr_list]
  1119.         pop     [ebp+NTFS.ntfs_attr_offs]
  1120.         pop     [ebp+NTFS.ntfs_attr_iBaseRecord]
  1121.         pop     [ebp+NTFS.ntfs_attr_iRecord]
  1122.         jc      .ret
  1123.         cmp     edx, [ebp+NTFS.frs_size]
  1124.         jnz     .errret
  1125.         mov     eax, [ebp+NTFS.frs_buffer]
  1126.         cmp     dword [eax], 'FILE'
  1127.         jnz     .errret
  1128.         push    ebx
  1129.         mov     ebx, eax
  1130.         call    ntfs_restore_usa_frs
  1131.         pop     ebx
  1132.         jc      .errret
  1133. .ret:
  1134.         pop     edx ecx
  1135.         ret
  1136. .errret:
  1137.         pop     edx ecx
  1138.         xor     eax, eax
  1139.         stc
  1140.         ret
  1141.  
  1142. ntfs_restore_usa_frs:
  1143.         mov     eax, [ebp+NTFS.frs_size]
  1144. ntfs_restore_usa:
  1145. ;   in:
  1146. ; ebx -> record
  1147. ; eax = size in bytes
  1148.         pushad
  1149.         shr     eax, 9
  1150.         mov     ecx, eax
  1151.         inc     eax
  1152.         cmp     [ebx+6], ax
  1153.         jnz     .err
  1154.         movzx   eax, word [ebx+4]
  1155.         lea     esi, [eax+ebx]
  1156.         lodsw
  1157.         mov     edx, eax
  1158.         lea     edi, [ebx+0x1FE]
  1159. @@:
  1160.         cmp     [edi], dx
  1161.         jnz     .err
  1162.         lodsw
  1163.         stosw
  1164.         add     edi, 0x1FE
  1165.         loop    @b
  1166.         popad
  1167.         clc
  1168.         ret
  1169. .err:
  1170.         popad
  1171.         stc
  1172.         ret
  1173.  
  1174. ntfs_decode_mcb_entry:
  1175. ;   in:
  1176. ; esi -> MCB entry
  1177. ; esp -> buffer (16 bytes)
  1178. ;   out:
  1179. ; esi -> next MCB entry
  1180. ; esp -> data run size
  1181. ; esp+8 -> cluster (delta)
  1182. ; CF=0 -> MCB end
  1183.         push    eax ecx edi
  1184.         lea     edi, [esp+16]
  1185.         xor     eax, eax
  1186.         lodsb
  1187.         test    al, al
  1188.         jz      .end
  1189.         mov     ecx, eax
  1190.         and     ecx, 0xF
  1191.         cmp     ecx, 8
  1192.         ja      .end
  1193.         push    ecx
  1194.         rep movsb
  1195.         pop     ecx
  1196.         sub     ecx, 8
  1197.         neg     ecx
  1198.         cmp     byte [esi-1], 80h
  1199.         jae     .end
  1200.         push    eax
  1201.         xor     eax, eax
  1202.         rep stosb
  1203.         pop     ecx
  1204.         shr     ecx, 4
  1205.         cmp     ecx, 8
  1206.         ja      .end
  1207.         push    ecx
  1208.         rep movsb
  1209.         pop     ecx
  1210.         sub     ecx, 8
  1211.         neg     ecx
  1212.         cmp     byte [esi-1], 80h
  1213.         cmc
  1214.         sbb     eax, eax
  1215.         rep stosb
  1216.         stc
  1217. .end:
  1218.         pop     edi ecx eax
  1219.         ret
  1220.  
  1221. unichar_toupper:
  1222.         push    eax
  1223.         call    uni2ansi_char
  1224.         cmp     al, '_'
  1225.         jz      .unk
  1226.         add     esp, 4
  1227.         call    char_toupper
  1228.         jmp     ansi2uni_char
  1229. .unk:
  1230.         pop     eax
  1231.         ret
  1232.  
  1233. ntfs_find_lfn:
  1234. ; in: [esi]+[esp+4] = name
  1235. ;   out:
  1236. ; [ebp+NTFS.ntfs_cur_iRecord] = number of MFT fileRecord
  1237. ; eax -> index in the parent index node
  1238. ; CF=1 -> file not found, eax=0 -> error
  1239.         mov     [ebp+NTFS.ntfs_cur_iRecord], 5   ; start parse from root cluster
  1240. .doit2:
  1241.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90   ; $INDEX_ROOT
  1242.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1243.         mov     eax, [ebp+NTFS.cur_index_size]
  1244.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1245.         mov     eax, [ebp+NTFS.cur_index_buf]
  1246.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1247.         call    ntfs_read_attr
  1248.         mov     eax, 0
  1249.         jnc     @f
  1250. .ret:
  1251.         ret     4
  1252. @@:
  1253.         cmp     [ebp+NTFS.ntfs_cur_read], 0x20
  1254.         jc      .ret
  1255.         pushad
  1256.         mov     esi, [ebp+NTFS.cur_index_buf]
  1257.         mov     eax, [esi+14h]
  1258.         add     eax, 10h
  1259.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1260.         jae     .readok1
  1261.         add     eax, 1FFh
  1262.         shr     eax, 9
  1263.         cmp     eax, [ebp+NTFS.cur_index_size]
  1264.         ja      @f
  1265. .stc_ret:
  1266.         popad
  1267.         stc
  1268.         ret     4
  1269. @@:
  1270. ; reallocate
  1271.         push    eax
  1272.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1273.         pop     eax
  1274.         mov     [ebp+NTFS.cur_index_size], eax
  1275.         stdcall kernel_alloc, eax
  1276.         test    eax, eax
  1277.         jnz     @f
  1278.         and     [ebp+NTFS.cur_index_size], 0
  1279.         and     [ebp+NTFS.cur_index_buf], 0
  1280.         jmp     .stc_ret
  1281. @@:
  1282.         mov     [ebp+NTFS.cur_index_buf], eax
  1283.         popad
  1284.         jmp     .doit2
  1285. .readok1:
  1286.         mov     edx, [esi+8]    ; subnode_size
  1287.         shr     edx, 9
  1288.         cmp     edx, [ebp+NTFS.cur_index_size]
  1289.         jbe     .ok2
  1290.         push    esi edx
  1291.         stdcall kernel_alloc, edx
  1292.         pop     edx esi
  1293.         test    eax, eax
  1294.         jz      .stc_ret
  1295.         mov     edi, eax
  1296.         mov     ecx, [ebp+NTFS.cur_index_size]
  1297.         shl     ecx, 9-2
  1298.         rep movsd
  1299.         mov     esi, eax
  1300.         mov     [ebp+NTFS.cur_index_size], edx
  1301.         push    esi edx
  1302.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1303.         pop     edx esi
  1304.         mov     [ebp+NTFS.cur_index_buf], esi
  1305. .ok2:
  1306.         add     esi, 10h
  1307.         mov     edi, [esp+4]
  1308. ; edi -> name, esi -> current index data, edx = subnode size
  1309. .scanloop:
  1310.         add     esi, [esi]
  1311. .scanloopint:
  1312.         test    byte [esi+0Ch], 2
  1313.         jnz     .subnode
  1314.         push    esi
  1315.         add     esi, 0x52
  1316.         movzx   ecx, byte [esi-2]
  1317.         push    edi
  1318. @@:
  1319.         lodsw
  1320.         call    unichar_toupper
  1321.         push    eax
  1322.         mov     al, [edi]
  1323.         inc     edi
  1324.         cmp     al, '/'
  1325.         jz      .slash
  1326.         call    char_toupper
  1327.         call    ansi2uni_char
  1328.         cmp     ax, [esp]
  1329.         pop     eax
  1330.         loopz   @b
  1331.         jz      .found
  1332.         pop     edi
  1333.         pop     esi
  1334.         jb      .subnode
  1335. .scanloopcont:
  1336.         movzx   eax, word [esi+8]
  1337.         add     esi, eax
  1338.         jmp     .scanloopint
  1339. .slash:
  1340.         pop     eax
  1341.         pop     edi
  1342.         pop     esi
  1343. .subnode:
  1344.         test    byte [esi+0Ch], 1
  1345.         jz      .notfound
  1346.         movzx   eax, word [esi+8]
  1347.         mov     eax, [esi+eax-8]
  1348.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  1349.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1350.         mov     [ebp+NTFS.ntfs_cur_attr], 0xA0   ; $INDEX_ALLOCATION
  1351.         mov     [ebp+NTFS.ntfs_cur_size], edx
  1352.         mov     eax, [ebp+NTFS.cur_index_buf]
  1353.         mov     esi, eax
  1354.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1355.         push    edx
  1356.         call    ntfs_read_attr
  1357.         pop     edx
  1358.         mov     eax, edx
  1359.         shl     eax, 9
  1360.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1361.         jnz     .err
  1362.         cmp     dword [esi], 'INDX'
  1363.         jnz     .err
  1364.         mov     [ebp+NTFS.ntfs_cur_buf], esi
  1365.         mov     ebx, esi
  1366.         call    ntfs_restore_usa
  1367.         jc      .err
  1368.         add     esi, 0x18
  1369.         jmp     .scanloop
  1370. .notfound:
  1371.         mov     [esp+1Ch], esi
  1372. .err:
  1373.         popad
  1374.         stc
  1375.         ret     4
  1376. .found:
  1377.         cmp     byte [edi], 0
  1378.         jz      .done
  1379.         cmp     byte [edi], '/'
  1380.         jz      .next
  1381.         pop     edi
  1382.         pop     esi
  1383.         jmp     .scanloopcont
  1384. .done:
  1385. .next:
  1386.         pop     esi
  1387.         pop     esi
  1388.         mov     eax, [esi]
  1389.         mov     [ebp+NTFS.ntfs_cur_iRecord], eax
  1390.         mov     [esp+1Ch], esi
  1391.         mov     [esp+4], edi
  1392.         popad
  1393.         inc     esi
  1394.         cmp     byte [esi-1], 0
  1395.         jnz     .doit2
  1396.         cmp     dword [esp+4], 0
  1397.         jz      @f
  1398.         mov     esi, [esp+4]
  1399.         mov     dword [esp+4], 0
  1400.         jmp     .doit2
  1401. @@:
  1402.         ret     4
  1403.  
  1404. ;----------------------------------------------------------------
  1405. ntfs_ReadFile:
  1406.         cmp     byte [esi], 0
  1407.         jnz     @f
  1408.         or      ebx, -1
  1409.         movi    eax, ERROR_ACCESS_DENIED
  1410.         ret
  1411. @@:
  1412.         call    ntfs_lock
  1413.         stdcall ntfs_find_lfn, [esp+4]
  1414.         jnc     .found
  1415.         call    ntfs_unlock
  1416.         or      ebx, -1
  1417.         movi    eax, ERROR_FILE_NOT_FOUND
  1418.         ret
  1419. .found:
  1420.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80   ; $DATA
  1421.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1422.         and     [ebp+NTFS.ntfs_cur_size], 0
  1423.         call    ntfs_read_attr
  1424.         jnc     @f
  1425.         call    ntfs_unlock
  1426.         or      ebx, -1
  1427.         movi    eax, ERROR_ACCESS_DENIED
  1428.         ret
  1429. @@:
  1430.         pushad
  1431.         and     dword [esp+10h], 0
  1432.         xor     eax, eax
  1433.         cmp     dword [ebx+8], 0x200
  1434.         jb      @f
  1435. .eof0:
  1436.         popad
  1437.         xor     ebx, ebx
  1438. .eof:
  1439.         push    ERROR_END_OF_FILE
  1440.         call    ntfs_unlock
  1441.         pop     eax
  1442.         ret
  1443. @@:
  1444.         mov     ecx, [ebx+12]
  1445.         mov     edx, [ebx+16]
  1446.         mov     eax, [ebx+4]
  1447.         test    eax, 0x1FF
  1448.         jz      .alignedstart
  1449.         push    edx
  1450.         mov     edx, [ebx+8]
  1451.         shrd    eax, edx, 9
  1452.         pop     edx
  1453.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1454.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1455.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1456.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1457.         call    ntfs_read_attr.continue
  1458.         mov     eax, [ebx+4]
  1459.         and     eax, 0x1FF
  1460.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf+eax]
  1461.         sub     eax, [ebp+NTFS.ntfs_cur_read]
  1462.         jae     .eof0
  1463.         neg     eax
  1464.         push    ecx
  1465.         cmp     ecx, eax
  1466.         jb      @f
  1467.         mov     ecx, eax
  1468. @@:
  1469.         mov     [esp+10h+4], ecx
  1470.         mov     edi, edx
  1471.         rep movsb
  1472.         mov     edx, edi
  1473.         pop     ecx
  1474.         sub     ecx, [esp+10h]
  1475.         jnz     @f
  1476. .retok:
  1477.         popad
  1478.         call    ntfs_unlock
  1479.         xor     eax, eax
  1480.         ret
  1481. @@:
  1482.         cmp     [ebp+NTFS.ntfs_cur_read], 0x200
  1483.         jz      .alignedstart
  1484. .eof_ebx:
  1485.         popad
  1486.         jmp     .eof
  1487. .alignedstart:
  1488.         mov     eax, [ebx+4]
  1489.         push    edx
  1490.         mov     edx, [ebx+8]
  1491.         add     eax, 511
  1492.         adc     edx, 0
  1493.         shrd    eax, edx, 9
  1494.         pop     edx
  1495.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1496.         mov     [ebp+NTFS.ntfs_cur_buf], edx
  1497.         mov     eax, ecx
  1498.         shr     eax, 9
  1499.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1500.         add     eax, [ebp+NTFS.ntfs_cur_offs]
  1501.         push    eax
  1502.         call    ntfs_read_attr.continue
  1503.         pop     [ebp+NTFS.ntfs_cur_offs]
  1504.         mov     eax, [ebp+NTFS.ntfs_cur_read]
  1505.         add     [esp+10h], eax
  1506.         mov     eax, ecx
  1507.         and     eax, not 0x1FF
  1508.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1509.         jnz     .eof_ebx
  1510.         and     ecx, 0x1FF
  1511.         jz      .retok
  1512.         add     edx, [ebp+NTFS.ntfs_cur_read]
  1513.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1514.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1515.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1516.         call    ntfs_read_attr.continue
  1517.         cmp     [ebp+NTFS.ntfs_cur_read], ecx
  1518.         jb      @f
  1519.         mov     [ebp+NTFS.ntfs_cur_read], ecx
  1520. @@:
  1521.         xchg    ecx, [ebp+NTFS.ntfs_cur_read]
  1522.         push    ecx
  1523.         mov     edi, edx
  1524.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf]
  1525.         add     [esp+10h+4], ecx
  1526.         rep movsb
  1527.         pop     ecx
  1528.         xor     eax, eax
  1529.         cmp     ecx, [ebp+NTFS.ntfs_cur_read]
  1530.         jz      @f
  1531.         mov     al, ERROR_END_OF_FILE
  1532. @@:
  1533.         mov     [esp+1Ch], eax
  1534.         call    ntfs_unlock
  1535.         popad
  1536.         ret
  1537.  
  1538. ;----------------------------------------------------------------
  1539. ntfs_ReadFolder:
  1540.         call    ntfs_lock
  1541.         mov     eax, 5          ; root cluster
  1542.         cmp     byte [esi], 0
  1543.         jz      .doit
  1544.         stdcall ntfs_find_lfn, [esp+4]
  1545.         jnc     .doit2
  1546. .notfound:
  1547.         or      ebx, -1
  1548.         push    ERROR_FILE_NOT_FOUND
  1549. .pop_ret:
  1550.         call    ntfs_unlock
  1551.         pop     eax
  1552.         ret
  1553. .doit:
  1554.         mov     [ebp+NTFS.ntfs_cur_iRecord], eax
  1555. .doit2:
  1556.         mov     [ebp+NTFS.ntfs_cur_attr], 0x10   ; $STANDARD_INFORMATION
  1557.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1558.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1559.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1560.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1561.         call    ntfs_read_attr
  1562.         jc      .notfound
  1563.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90   ; $INDEX_ROOT
  1564.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1565.         mov     eax, [ebp+NTFS.cur_index_size]
  1566.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1567.         mov     eax, [ebp+NTFS.cur_index_buf]
  1568.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1569.         call    ntfs_read_attr
  1570.         jnc     .ok
  1571.         test    eax, eax
  1572.         jz      .notfound
  1573.         or      ebx, -1
  1574.         push    ERROR_DEVICE
  1575.         jmp     .pop_ret
  1576. .ok:
  1577.         cmp     [ebp+NTFS.ntfs_cur_read], 0x20
  1578.         jae     @f
  1579.         or      ebx, -1
  1580. .fserr:
  1581.         push    ERROR_FAT_TABLE
  1582.         jmp     .pop_ret
  1583. @@:
  1584.         pushad
  1585.         mov     esi, [ebp+NTFS.cur_index_buf]
  1586.         mov     eax, [esi+14h]
  1587.         add     eax, 10h
  1588.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1589.         jae     .readok1
  1590.         add     eax, 1FFh
  1591.         shr     eax, 9
  1592.         cmp     eax, [ebp+NTFS.cur_index_size]
  1593.         ja      @f
  1594.         popad
  1595.         jmp     .fserr
  1596. @@:
  1597. ; reallocate
  1598.         push    eax
  1599.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1600.         pop     eax
  1601.         mov     [ebp+NTFS.cur_index_size], eax
  1602.         stdcall kernel_alloc, eax
  1603.         test    eax, eax
  1604.         jnz     @f
  1605.         and     [ebp+NTFS.cur_index_size], 0
  1606.         and     [ebp+NTFS.cur_index_buf], 0
  1607. .nomem:
  1608.         call    ntfs_unlock
  1609.         popad
  1610.         or      ebx, -1
  1611.         movi    eax, ERROR_OUT_OF_MEMORY
  1612.         ret
  1613. @@:
  1614.         mov     [ebp+NTFS.cur_index_buf], eax
  1615.         popad
  1616.         jmp     .doit2
  1617. .readok1:
  1618.         mov     edx, [esi+8]    ; subnode_size
  1619.         shr     edx, 9
  1620.         mov     [ebp+NTFS.cur_subnode_size], edx
  1621.         cmp     edx, [ebp+NTFS.cur_index_size]
  1622.         jbe     .ok2
  1623.         push    esi edx
  1624.         stdcall kernel_alloc, edx
  1625.         pop     edx esi
  1626.         test    eax, eax
  1627.         jz      .nomem
  1628.         mov     edi, eax
  1629.         mov     ecx, [ebp+NTFS.cur_index_size]
  1630.         shl     ecx, 9-2
  1631.         rep movsd
  1632.         mov     esi, eax
  1633.         mov     [ebp+NTFS.cur_index_size], edx
  1634.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1635.         mov     [ebp+NTFS.cur_index_buf], esi
  1636. .ok2:
  1637.         add     esi, 10h
  1638.         mov     edx, [ebx+16]
  1639.         push    dword [ebx+8]   ; read ANSI/UNICODE name
  1640. ; init header
  1641.         mov     edi, edx
  1642.         mov     ecx, 32/4
  1643.         xor     eax, eax
  1644.         rep stosd
  1645.         mov     byte [edx], 1   ; version
  1646.         mov     ecx, [ebx+12]
  1647.         mov     ebx, [ebx+4]
  1648.         push    edx
  1649.         mov     edx, esp
  1650. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1651. ; ecx = number of blocks to read
  1652. ; edx -> parameters block: dd <output>, dd <flags>
  1653.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 5
  1654.         jz      .skip_specials
  1655. ; dot and dotdot entries
  1656.         push    esi
  1657.         xor     esi, esi
  1658.         call    .add_special_entry
  1659.         inc     esi
  1660.         call    .add_special_entry
  1661.         pop     esi
  1662. .skip_specials:
  1663. ; at first, dump index root
  1664.         add     esi, [esi]
  1665. .dump_root:
  1666.         test    byte [esi+0Ch], 2
  1667.         jnz     .dump_root_done
  1668.         call    .add_entry
  1669.         movzx   eax, word [esi+8]
  1670.         add     esi, eax
  1671.         jmp     .dump_root
  1672. .dump_root_done:
  1673. ; now dump all subnodes
  1674.         push    ecx edi
  1675.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  1676.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  1677.         mov     ecx, 0x400/4
  1678.         xor     eax, eax
  1679.         rep stosd
  1680.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0   ; $BITMAP
  1681.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1682.         mov     [ebp+NTFS.ntfs_cur_size], 2
  1683.         call    ntfs_read_attr
  1684.         pop     edi ecx
  1685.         push    0       ; save offset in $BITMAP attribute
  1686.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1687. .dumploop:
  1688.         mov     [ebp+NTFS.ntfs_cur_attr], 0xA0
  1689.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1690.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1691.         mov     eax, [ebp+NTFS.cur_index_buf]
  1692.         mov     esi, eax
  1693.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1694.         push    [ebp+NTFS.ntfs_cur_offs]
  1695.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  1696.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1697.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1698.         call    ntfs_read_attr
  1699.         pop     [ebp+NTFS.ntfs_cur_offs]
  1700.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1701.         shl     eax, 9
  1702.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1703.         jnz     .done
  1704.         push    eax
  1705.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  1706.         and     eax, 0x400*8-1
  1707.         bt      dword [ebp+NTFS.ntfs_bitmap_buf], eax
  1708.         pop     eax
  1709.         jnc     .dump_subnode_done
  1710.         cmp     dword [esi], 'INDX'
  1711.         jnz     .dump_subnode_done
  1712.         push    ebx
  1713.         mov     ebx, esi
  1714.         call    ntfs_restore_usa
  1715.         pop     ebx
  1716.         jc      .dump_subnode_done
  1717.         add     esi, 0x18
  1718.         add     esi, [esi]
  1719. .dump_subnode:
  1720.         test    byte [esi+0Ch], 2
  1721.         jnz     .dump_subnode_done
  1722.         call    .add_entry
  1723.         movzx   eax, word [esi+8]
  1724.         add     esi, eax
  1725.         jmp     .dump_subnode
  1726. .dump_subnode_done:
  1727.         inc     [ebp+NTFS.ntfs_cur_offs]
  1728.         test    [ebp+NTFS.ntfs_cur_offs], 0x400*8-1
  1729.         jnz     .dumploop
  1730.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0
  1731.         push    ecx edi
  1732.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  1733.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  1734.         mov     ecx, 0x400/4
  1735.         xor     eax, eax
  1736.         rep stosd
  1737.         pop     edi ecx
  1738.         pop     eax
  1739.         push    [ebp+NTFS.ntfs_cur_offs]
  1740.         inc     eax
  1741.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1742.         mov     [ebp+NTFS.ntfs_cur_size], 2
  1743.         push    eax
  1744.         call    ntfs_read_attr
  1745.         pop     eax
  1746.         pop     [ebp+NTFS.ntfs_cur_offs]
  1747.         push    eax
  1748.         jmp     .dumploop
  1749. .done:
  1750.         pop     eax
  1751.         pop     edx
  1752.         mov     ebx, [edx+4]
  1753.         pop     edx
  1754.         xor     eax, eax
  1755.         dec     ecx
  1756.         js      @f
  1757.         mov     al, ERROR_END_OF_FILE
  1758. @@:
  1759.         mov     [esp+1Ch], eax
  1760.         mov     [esp+10h], ebx
  1761.         call    ntfs_unlock
  1762.         popad
  1763.         ret
  1764.  
  1765. .add_special_entry:
  1766.         mov     eax, [edx]
  1767.         inc     dword [eax+8]   ; new file found
  1768.         dec     ebx
  1769.         jns     .ret
  1770.         dec     ecx
  1771.         js      .ret
  1772.         inc     dword [eax+4]   ; new file block copied
  1773.         mov     eax, [edx+4]
  1774.         mov     [edi+4], eax
  1775. ;        mov     eax, dword [ntfs_bitmap_buf+0x20]
  1776. ;        or      al, 0x10
  1777.         mov     eax, 0x10
  1778.         stosd
  1779.         scasd
  1780.         push    edx
  1781.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf]
  1782.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+4]
  1783.         call    ntfs_datetime_to_bdfe
  1784.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf+0x18]
  1785.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+0x1C]
  1786.         call    ntfs_datetime_to_bdfe
  1787.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf+8]
  1788.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+0xC]
  1789.         call    ntfs_datetime_to_bdfe
  1790.         pop     edx
  1791.         xor     eax, eax
  1792.         stosd
  1793.         stosd
  1794.         mov     al, '.'
  1795.         push    edi ecx
  1796.         lea     ecx, [esi+1]
  1797.         test    byte [edi-0x24], 1
  1798.         jz      @f
  1799.         rep stosw
  1800.         pop     ecx
  1801.         xor     eax, eax
  1802.         stosw
  1803.         pop     edi
  1804.         add     edi, 520
  1805.         ret
  1806. @@:
  1807.         rep stosb
  1808.         pop     ecx
  1809.         xor     eax, eax
  1810.         stosb
  1811.         pop     edi
  1812.         add     edi, 264
  1813. .ret:
  1814.         ret
  1815.  
  1816. .add_entry:
  1817. ; do not return DOS 8.3 names
  1818.         cmp     byte [esi+0x51], 2
  1819.         jz      .ret
  1820. ; do not return system files
  1821. ; ... note that there will be no bad effects if system files also were reported ...
  1822.         cmp     dword [esi], 0x10
  1823.         jb      .ret
  1824.         mov     eax, [edx]
  1825.         inc     dword [eax+8]   ; new file found
  1826.         dec     ebx
  1827.         jns     .ret
  1828.         dec     ecx
  1829.         js      .ret
  1830.         inc     dword [eax+4]   ; new file block copied
  1831.         mov     eax, [edx+4]    ; flags
  1832.         call    ntfs_direntry_to_bdfe
  1833.         push    ecx esi edi
  1834.         movzx   ecx, byte [esi+0x50]
  1835.         add     esi, 0x52
  1836.         test    byte [edi-0x24], 1
  1837.         jz      .ansi
  1838.         shr     ecx, 1
  1839.         rep movsd
  1840.         adc     ecx, ecx
  1841.         rep movsw
  1842.         and     word [edi], 0
  1843.         pop     edi
  1844.         add     edi, 520
  1845.         pop     esi ecx
  1846.         ret
  1847. .ansi:
  1848.         jecxz   .skip
  1849. @@:
  1850.         lodsw
  1851.         call    uni2ansi_char
  1852.         stosb
  1853.         loop    @b
  1854. .skip:
  1855.         xor     al, al
  1856.         stosb
  1857.         pop     edi
  1858.         add     edi, 264
  1859.         pop     esi ecx
  1860.         ret
  1861.  
  1862. ntfs_direntry_to_bdfe:
  1863.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1864.         mov     eax, [esi+48h]
  1865.         test    eax, 0x10000000
  1866.         jz      @f
  1867.         and     eax, not 0x10000000
  1868.         or      al, 0x10
  1869. @@:
  1870.         stosd
  1871.         scasd
  1872.         push    edx
  1873.         mov     eax, [esi+0x18]
  1874.         mov     edx, [esi+0x1C]
  1875.         call    ntfs_datetime_to_bdfe
  1876.         mov     eax, [esi+0x30]
  1877.         mov     edx, [esi+0x34]
  1878.         call    ntfs_datetime_to_bdfe
  1879.         mov     eax, [esi+0x20]
  1880.         mov     edx, [esi+0x24]
  1881.         call    ntfs_datetime_to_bdfe
  1882.         pop     edx
  1883.         mov     eax, [esi+0x40]
  1884.         stosd
  1885.         mov     eax, [esi+0x44]
  1886.         stosd
  1887.         ret
  1888.  
  1889. iglobal
  1890. _24             dd      24
  1891. _60             dd      60
  1892. _10000000       dd      10000000
  1893. days400year     dd      365*400+100-4+1
  1894. days100year     dd      365*100+25-1
  1895. days4year       dd      365*4+1
  1896. days1year       dd      365
  1897. months  dd  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1898. months2 dd  31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1899. _400            dd      400
  1900. _100            dd      100
  1901. endg
  1902.  
  1903. ntfs_datetime_to_bdfe:
  1904. ; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC
  1905.         push    eax
  1906.         mov     eax, edx
  1907.         xor     edx, edx
  1908.         div     [_10000000]
  1909.         xchg    eax, [esp]
  1910.         div     [_10000000]
  1911.         pop     edx
  1912.     .sec:
  1913. ; edx:eax = number of seconds since January 1, 1601
  1914.         push    eax
  1915.         mov     eax, edx
  1916.         xor     edx, edx
  1917.         div     [_60]
  1918.         xchg    eax, [esp]
  1919.         div     [_60]
  1920.         mov     [edi], dl
  1921.         pop     edx
  1922. ; edx:eax = number of minutes
  1923.         div     [_60]
  1924.         mov     [edi+1], dl
  1925. ; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32)
  1926.         xor     edx, edx
  1927.         div     [_24]
  1928.         mov     [edi+2], dl
  1929.         mov     [edi+3], byte 0
  1930. ; eax = number of days since January 1, 1601
  1931.         xor     edx, edx
  1932.         div     [days400year]
  1933.         imul    eax, 400
  1934.         add     eax, 1601
  1935.         mov     [edi+6], ax
  1936.         mov     eax, edx
  1937.         xor     edx, edx
  1938.         div     [days100year]
  1939.         cmp     al, 4
  1940.         jnz     @f
  1941.         dec     eax
  1942.         add     edx, [days100year]
  1943. @@:
  1944.         imul    eax, 100
  1945.         add     [edi+6], ax
  1946.         mov     eax, edx
  1947.         xor     edx, edx
  1948.         div     [days4year]
  1949.         shl     eax, 2
  1950.         add     [edi+6], ax
  1951.         mov     eax, edx
  1952.         xor     edx, edx
  1953.         div     [days1year]
  1954.         cmp     al, 4
  1955.         jnz     @f
  1956.         dec     eax
  1957.         add     edx, [days1year]
  1958. @@:
  1959.         add     [edi+6], ax
  1960.         push    esi edx
  1961.         mov     esi, months
  1962.         movzx   eax, word [edi+6]
  1963.         test    al, 3
  1964.         jnz     .noleap
  1965.         xor     edx, edx
  1966.         push    eax
  1967.         div     [_400]
  1968.         pop     eax
  1969.         test    edx, edx
  1970.         jz      .leap
  1971.         xor     edx, edx
  1972.         div     [_100]
  1973.         test    edx, edx
  1974.         jz      .noleap
  1975. .leap:
  1976.         mov     esi, months2
  1977. .noleap:
  1978.         pop     edx
  1979.         xor     eax, eax
  1980.         inc     eax
  1981. @@:
  1982.         sub     edx, [esi]
  1983.         jb      @f
  1984.         add     esi, 4
  1985.         inc     eax
  1986.         jmp     @b
  1987. @@:
  1988.         add     edx, [esi]
  1989.         pop     esi
  1990.         inc     edx
  1991.         mov     [edi+4], dl
  1992.         mov     [edi+5], al
  1993.         add     edi, 8
  1994.         ret
  1995.  
  1996. ;----------------------------------------------------------------
  1997. ntfs_CreateFolder:
  1998.         mov     [ebp+NTFS.ntfsFolder], 1
  1999.         jmp     @f
  2000.  
  2001. ntfs_CreateFile:
  2002.         mov     [ebp+NTFS.ntfsFolder], 0
  2003. @@:
  2004.         cmp     byte [esi], 0
  2005.         jnz     @f
  2006.         xor     ebx, ebx
  2007.         movi    eax, ERROR_ACCESS_DENIED
  2008.         ret
  2009. @@: ; 1. Search file
  2010.         call    ntfs_lock
  2011.         stdcall ntfs_find_lfn, [esp+4]
  2012.         jc      .notFound
  2013. ; found, rewrite
  2014.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 16
  2015.         jc      ntfsDenied
  2016.         cmp     [ebp+NTFS.ntfsFolder], 1
  2017.         jz      .folder
  2018.         cmp     [ebp+NTFS.ntfsFragmentCount], 1
  2019.         jnz     ntfsUnsupported     ; record fragmented
  2020. ; edit directory node
  2021.         mov     edi, [ebp+NTFS.cur_index_buf]
  2022.         cmp     dword [edi], 'INDX'
  2023.         jz      @f
  2024.         mov     esi, [ebp+NTFS.frs_buffer]
  2025.         mov     ecx, [esi+recordRealSize]
  2026.         shr     ecx, 2
  2027.         rep movsd
  2028.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  2029.         mov     cl, [esi+attributeOffset]
  2030.         sub     esi, [ebp+NTFS.frs_buffer]
  2031.         add     eax, ecx
  2032.         add     eax, esi
  2033. @@:
  2034.         mov     edx, [ebx+12]
  2035.         mov     [eax+fileRealSize], edx
  2036.         mov     dword [eax+fileRealSize+4], 0
  2037.         mov     eax, [ebp+NTFS.ntfsLastRead]
  2038.         mov     [ebp+NTFS.nodeLastRead], eax
  2039.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  2040.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  2041.         mov     [ebp+NTFS.ntfs_cur_size], 0
  2042.         call    ntfs_read_attr
  2043.         jc      ntfsFail
  2044.         mov     ecx, [ebp+NTFS.frs_buffer]
  2045.         mov     eax, edx
  2046.         xor     edx, edx
  2047.         cmp     word [ecx+baseRecordReuse], 0
  2048.         jnz     ntfsUnsupported     ; auxiliary record
  2049.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  2050.         cmp     word [ecx+attributeFlags], 0
  2051.         jnz     ntfsUnsupported
  2052.         push    ebx
  2053.         cmp     byte [ecx+nonResidentFlag], 0
  2054.         jz      @f
  2055.         cmp     [ecx+attributeRealSize+4], edx
  2056.         jnz     @f
  2057.         cmp     [ecx+attributeRealSize], eax
  2058.         jz      ntfs_WriteFile.writeNode
  2059. @@:
  2060.         jmp     ntfs_WriteFile.resizeAttribute
  2061.  
  2062. .folder:
  2063.         bt      dword [eax+fileFlags], 28
  2064.         jnc     ntfsDenied
  2065.         push    0
  2066.         jmp     ntfsOut
  2067.  
  2068. .notFound:  ; create
  2069.         test    eax, eax
  2070.         jz      ntfsFail
  2071.         cmp     [ebp+NTFS.ntfsFragmentCount], 1
  2072.         jnz     ntfsUnsupported     ; record fragmented
  2073. ; 2. Prepare directory record
  2074.         mov     ecx, esi
  2075. @@:         ; count characters
  2076.         inc     ecx
  2077.         cmp     byte [ecx], '/'
  2078.         jz      ntfsNotFound    ; path folder not found
  2079.         cmp     byte [ecx], 0
  2080.         jnz     @b
  2081.         sub     ecx, esi
  2082.         push    ecx
  2083.         lea     ecx, [ecx*2+52h+7]  ; precalculate index length
  2084.         and     ecx, not 7          ; align 8
  2085.         mov     edi, [ebp+NTFS.cur_index_buf]
  2086.         push    esi
  2087.         push    ecx
  2088.         cmp     dword [edi], 'INDX'
  2089.         jz      .indexRecord
  2090.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  2091.         mov     edx, [esi+recordRealSize]
  2092.         add     edx, ecx
  2093.         cmp     [esi+recordAllocatedSize], edx
  2094.         jnc     @f
  2095.         add     esp, 12
  2096.         jmp     ntfsUnsupported     ; indexAllocation required
  2097. @@:         ; index fits in the indexRoot
  2098.         mov     [esi+recordRealSize], edx
  2099.         mov     ecx, edx
  2100.         shr     ecx, 2
  2101.         rep movsd
  2102.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  2103.         sub     edi, [ebp+NTFS.frs_buffer]
  2104.         add     edi, [ebp+NTFS.cur_index_buf]
  2105.         mov     esi, [esp]
  2106.         add     [edi+sizeWithHeader], esi
  2107.         add     [edi+sizeWithoutHeader], esi
  2108.         mov     cl, [edi+attributeOffset]
  2109.         add     edi, ecx
  2110.         add     [edi+16+nodeRealSize], esi
  2111.         add     [edi+16+nodeAllocatedSize], esi
  2112.         sub     eax, [ebp+NTFS.cur_index_buf]
  2113.         add     eax, edi
  2114.         mov     edi, [ebp+NTFS.cur_index_buf]
  2115.         add     edi, edx
  2116.         sub     edi, 4
  2117.         jmp     .common
  2118.  
  2119. .indexRecord:
  2120.         mov     edx, [edi+28]
  2121.         add     edx, ecx
  2122.         cmp     [edi+32], edx
  2123.         jnc     @f
  2124.         add     esp, 12
  2125.         jmp     ntfsUnsupported     ; new node required
  2126. @@:         ; index fits in the node
  2127.         mov     [edi+28], edx
  2128.         lea     edi, [edi+edx+24-4]
  2129. .common:
  2130.         mov     esi, edi
  2131.         sub     esi, [esp]
  2132.         mov     ecx, esi
  2133.         sub     ecx, eax    ; eax = pointer in the node
  2134.         shr     ecx, 2
  2135.         inc     ecx
  2136.         std
  2137.         rep movsd           ; move forward, make space
  2138.         mov     ecx, [esp]
  2139.         shr     ecx, 2
  2140.         xor     eax, eax
  2141.         rep stosd
  2142.         cld
  2143.         add     edi, 4
  2144.         pop     ecx
  2145.         pop     esi
  2146.         mov     [edi+indexAllocatedSize], cx    ; fill index with data
  2147.         mov     eax, [esp]
  2148.         shl     eax, 1
  2149.         add     eax, 42h
  2150.         mov     [edi+indexRawSize], ax
  2151.         mov     eax, [ebp+NTFS.ntfs_attr_iRecord]
  2152.         mov     [edi+directoryRecordReference], eax
  2153.         mov     eax, [ebp+NTFS.frs_buffer]
  2154.         mov     eax, [eax+reuseCounter]
  2155.         mov     [edi+directoryReferenceReuse], ax
  2156.         mov     eax, [ebx+12]
  2157.         add     ecx, 30h+48h+8+18h+8
  2158.         add     ecx, eax
  2159.         mov     [ebp+NTFS.fileRealSize], eax
  2160.         mov     [edi+fileRealSize], eax
  2161.         cmp     [ebp+NTFS.frs_size], ecx
  2162.         jc      @f
  2163.         mov     eax, [ebx+16]
  2164.         mov     [ebp+NTFS.fileDataStart], eax
  2165.         xor     eax, eax
  2166. @@:
  2167.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2168.         shl     ecx, 9
  2169.         add     eax, ecx
  2170.         dec     eax
  2171.         xor     edx, edx
  2172.         div     ecx
  2173.         mov     [ebp+NTFS.fileDataSize], eax
  2174.         mul     ecx
  2175.         mov     [edi+fileAllocatedSize], eax
  2176.         pop     ecx
  2177.         mov     [ebp+NTFS.indexOffset], edi
  2178.         mov     [edi+fileNameLength], cl
  2179.         add     edi, 52h
  2180. @@:         ; record filename
  2181.         lodsb
  2182.         call    ansi2uni_char
  2183.         stosw
  2184.         dec     ecx
  2185.         jnz     @b
  2186.         mov     eax, [ebp+NTFS.ntfsLastRead]
  2187.         mov     [ebp+NTFS.nodeLastRead], eax
  2188.         cmp     [ebp+NTFS.ntfsFolder], 0
  2189.         jz      @f
  2190.         mov     edi, [ebp+NTFS.indexOffset]
  2191.         bts     dword [edi+fileFlags], 28
  2192.         jmp     .mftBitmap
  2193.  
  2194. @@: ; 3. File data
  2195.         cmp     [ebp+NTFS.fileDataSize], 0
  2196.         jz      .mftBitmap
  2197.         mov     edi, [ebp+NTFS.BitmapStart]
  2198.         call    ntfsSpaceAlloc
  2199.         jc      ntfsDiskFull
  2200.         mov     [ebp+NTFS.fileDataStart], eax
  2201.         mul     [ebp+NTFS.sectors_per_cluster]
  2202.         mov     ecx, [ebp+NTFS.fileRealSize]
  2203.         add     ecx, 511
  2204.         shr     ecx, 9
  2205.         mov     ebx, [ebx+16]
  2206.         call    fs_write64_app
  2207.         test    eax, eax
  2208.         jnz     ntfsDevice
  2209.     ; 4. MFT record
  2210. .mftBitmap: ; search for free record
  2211.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2212.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2213.         mov     al, -1
  2214.         add     edi, 3
  2215.         sub     ecx, 3
  2216.         repz scasb
  2217.         dec     edi
  2218.         movzx   eax, byte [edi]
  2219.         not     al
  2220.         bsf     ecx, eax
  2221.         jz      .extendBitmapMFT    ; no free records
  2222.         bts     [edi], ecx
  2223. ; get record location
  2224.         sub     edi, [ebp+NTFS.mftBitmapBuffer]
  2225.         shl     edi, 3
  2226.         add     edi, ecx
  2227.         mov     [ebp+NTFS.newMftRecord], edi
  2228.         mov     eax, [ebp+NTFS.frs_size]
  2229.         shr     eax, 9
  2230.         mul     edi
  2231.         mov     [ebp+NTFS.ntfs_cur_iRecord], 0
  2232.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  2233.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  2234.         mov     [ebp+NTFS.ntfs_cur_size], 1
  2235.         mov     eax, [ebp+NTFS.frs_buffer]
  2236.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  2237.         call    ntfs_read_attr
  2238.         cmp     [ebp+NTFS.ntfs_cur_read], 0
  2239.         jz      .extendMFT
  2240.         jmp     .mftRecord
  2241.  
  2242. .extendBitmapMFT:
  2243.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2244.         shl     eax, 9
  2245.         cmp     [ebp+NTFS.mftBitmapSize], eax
  2246.         jnc     ntfsUnsupported
  2247.         mov     [ebp+NTFS.ntfs_cur_iRecord], 0
  2248.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0
  2249.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  2250.         mov     [ebp+NTFS.ntfs_cur_size], 0
  2251.         call    ntfs_read_attr
  2252.         jc      ntfsFail
  2253.         mov     eax, [ebp+NTFS.mft_cluster]
  2254.         mul     [ebp+NTFS.sectors_per_cluster]
  2255.         cmp     eax, [ebp+NTFS.ntfsLastRead]
  2256.         jnz     ntfsUnsupported     ; auxiliary record
  2257.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2258.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2259.         add     edi, ecx
  2260.         mov     eax, ecx
  2261.         mov     edx, [ebp+NTFS.ntfs_attr_offs]
  2262.         add     ecx, 8
  2263.         mov     [edx+attributeRealSize], ecx
  2264.         mov     [edx+initialDataSize], ecx
  2265.         shl     eax, 3
  2266.         mov     [ebp+NTFS.newMftRecord], eax
  2267.         mov     dword [edi], 1
  2268.         mov     dword [edi+4], 0
  2269.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  2270.         call    ntfs_read_attr.newAttribute
  2271.         jc      ntfsFail
  2272.         mov     [ebp+NTFS.mftBitmapSize], ecx
  2273. .extendMFT:
  2274.         mov     eax, [ebp+NTFS.mft_cluster]
  2275.         mul     [ebp+NTFS.sectors_per_cluster]
  2276.         cmp     eax, [ebp+NTFS.ntfsLastRead]
  2277.         jnz     ntfsUnsupported     ; auxiliary record
  2278.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  2279.         mov     eax, [ecx+attributeRealSize]
  2280.         mov     edx, [ecx+attributeRealSize+4]
  2281.         xor     ax, ax
  2282.         add     eax, 10000h
  2283.         adc     edx, 0
  2284.         push    [ebp+NTFS.fileDataStart]
  2285.         push    [ebp+NTFS.fileDataSize]
  2286.         call    resizeAttribute
  2287.         jc      ntfsErrorPop2
  2288.         mov     eax, [ebp+NTFS.frs_buffer]
  2289.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  2290.         call    writeRecord     ; $MFT
  2291.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  2292.         mul     [ebp+NTFS.sectors_per_cluster]
  2293.         mov     ebx, [ebp+NTFS.frs_buffer]
  2294.         movzx   ecx, word [ebx+updateSequenceSize]
  2295.         dec     ecx
  2296.         call    fs_write64_sys  ; $MFTMirr
  2297.         call    ntfsSpaceClean
  2298.         pop     [ebp+NTFS.fileDataSize]
  2299.         pop     [ebp+NTFS.fileDataStart]
  2300. .mftRecord:
  2301.         mov     ecx, [ebp+NTFS.frs_size]
  2302.         shr     ecx, 2
  2303.         mov     edi, [ebp+NTFS.frs_buffer]
  2304.         xor     eax, eax
  2305.         rep stosd
  2306.         mov     edi, [ebp+NTFS.frs_buffer]
  2307. ; record header
  2308.         mov     eax, [ebp+NTFS.frs_size]
  2309.         mov     [edi+recordAllocatedSize], eax
  2310.         shr     eax, 9
  2311.         inc     eax
  2312.         mov     [edi+updateSequenceSize], al
  2313.         mov     dword[edi], 'FILE'
  2314.         mov     byte [edi+updateSequenceOffset], 2ah
  2315.         mov     byte [edi+hardLinkCounter], 1
  2316.         mov     byte [edi+attributeOffset], 30h
  2317.         mov     byte [edi+newAttributeID], 3
  2318.         rdtsc
  2319.         mov     [edi+2ah], ax
  2320.         add     edi, 30h
  2321. ; $StandardInformation
  2322.         mov     byte [edi+attributeType], 10h
  2323.         mov     byte [edi+sizeWithHeader], 48h
  2324.         mov     byte [edi+sizeWithoutHeader], 30h
  2325.         mov     byte [edi+attributeOffset], 18h
  2326.         add     edi, 48h
  2327. ; $FileName
  2328.         mov     esi, [ebp+NTFS.indexOffset]
  2329.         mov     byte [edi+attributeType], 30h
  2330.         mov     byte [edi+attributeID], 1
  2331.         mov     byte [edi+attributeOffset], 18h
  2332.         mov     byte [edi+indexedFlag], 1
  2333.         mov     cx, [esi+indexRawSize]
  2334.         mov     [edi+sizeWithoutHeader], ecx
  2335.         mov     cx, [esi+indexAllocatedSize]
  2336.         add     ecx, 8
  2337.         mov     [edi+sizeWithHeader], ecx
  2338.         add     edi, 18h
  2339.         add     esi, 16
  2340.         sub     ecx, 18h
  2341.         shr     ecx, 2
  2342.         rep movsd
  2343.         mov     byte [edi+sizeWithHeader], 50h
  2344.         mov     byte [edi+attributeID], 2
  2345.         cmp     [ebp+NTFS.ntfsFolder], 1
  2346.         jz      .indexRoot
  2347. ; $Data
  2348.         mov     byte [edi+attributeType], 80h
  2349.         mov     eax, [ebp+NTFS.fileDataSize]
  2350.         test    eax, eax
  2351.         jz      .resident
  2352.         mov     esi, [ebp+NTFS.indexOffset]
  2353.         dec     eax
  2354.         mov     [edi+lastVCN], eax
  2355.         mov     byte [edi+nonResidentFlag], 1
  2356.         mov     byte [edi+dataRunsOffset], 40h
  2357.         mov     eax, [esi+fileAllocatedSize]
  2358.         mov     [edi+attributeAllocatedSize], eax
  2359.         mov     eax, [esi+fileRealSize]
  2360.         mov     [edi+attributeRealSize], eax
  2361.         mov     [edi+initialDataSize], eax
  2362.         push    edi
  2363.         mov     esi, edi
  2364.         add     edi, 40h
  2365.         call    createMcbEntry
  2366.         inc     edi
  2367.         jmp     @f
  2368.  
  2369. .resident:
  2370.         mov     ecx, [ebp+NTFS.fileRealSize]
  2371.         mov     [edi+sizeWithoutHeader], ecx
  2372.         mov     byte [edi+attributeOffset], 18h
  2373.         push    edi
  2374.         mov     esi, [ebp+NTFS.fileDataStart]
  2375.         add     edi, 18h
  2376.         rep movsb
  2377. @@:
  2378.         mov     eax, edi
  2379.         pop     edi
  2380.         sub     eax, edi
  2381.         add     eax, 7
  2382.         and     eax, not 7
  2383.         mov     [edi+sizeWithHeader], eax
  2384.         add     edi, eax
  2385.         mov     al, 1
  2386.         jmp     @f
  2387.  
  2388. .indexRoot:
  2389.         mov     byte [edi+attributeType], 90h
  2390.         mov     byte [edi+nameLength], 4
  2391.         mov     byte [edi+nameOffset], 18h
  2392.         mov     byte [edi+sizeWithoutHeader], 30h
  2393.         mov     byte [edi+attributeOffset], 20h
  2394.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2395.         mov     dword[edi+18h+4], 300033h
  2396.         mov     byte [edi+20h+attributeType], 30h
  2397.         mov     byte [edi+20h+collationRule], 1
  2398.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2399.         shl     eax, 9
  2400.         mov     [edi+20h+indexRecordSize], eax
  2401.         mov     byte [edi+20h+indexRecordSizeClus], 1
  2402.         mov     byte [edi+30h+indexOffset], 16
  2403.         mov     byte [edi+30h+nodeRealSize], 32
  2404.         mov     byte [edi+30h+nodeAllocatedSize], 32
  2405.         mov     byte [edi+40h+indexAllocatedSize], 16
  2406.         mov     byte [edi+40h+indexFlags], 2
  2407.         add     edi, 50h
  2408.         mov     al, 3
  2409. @@:
  2410.         mov     esi, [ebp+NTFS.frs_buffer]
  2411.         mov     dword [edi], -1
  2412.         mov     dword [edi+4], 0
  2413.         add     edi, 8
  2414.         sub     edi, esi
  2415.         mov     [ebp+NTFS.ntfs_cur_buf], esi
  2416.         mov     [esi+recordFlags], al
  2417.         mov     [esi+recordRealSize], edi
  2418.         call    writeRecord
  2419.         test    eax, eax
  2420.         jnz     ntfsDevice
  2421. ; write MFT bitmap
  2422.         mov     eax, [ebp+NTFS.newMftRecord]
  2423.         shr     eax, 3+9
  2424.         mov     ebx, eax
  2425.         shl     ebx, 9
  2426.         add     eax, [ebp+NTFS.mftBitmapLocation]
  2427.         add     ebx, [ebp+NTFS.mftBitmapBuffer]
  2428.         mov     ecx, 1
  2429.         xor     edx, edx
  2430.         call    fs_write64_sys
  2431.         test    eax, eax
  2432.         jnz     ntfsDevice
  2433. ; 5. Write partition bitmap
  2434.         cmp     [ebp+NTFS.ntfsFolder], 1
  2435.         jz      @f
  2436.         mov     eax, [ebp+NTFS.fileDataStart]
  2437.         mov     ecx, [ebp+NTFS.fileDataSize]
  2438.         test    ecx, ecx
  2439.         jz      @f
  2440.         add     ecx, eax
  2441.         add     ecx, 4095
  2442.         shr     ecx, 3+9
  2443.         shr     eax, 3+9
  2444.         sub     ecx, eax
  2445.         mov     ebx, eax
  2446.         shl     ebx, 9
  2447.         add     eax, [ebp+NTFS.BitmapLocation]
  2448.         add     ebx, [ebp+NTFS.BitmapBuffer]
  2449.         xor     edx, edx
  2450.         call    fs_write64_app
  2451.         test    eax, eax
  2452.         jnz     ntfsDevice
  2453. @@:
  2454.         mov     edi, [ebp+NTFS.indexOffset]
  2455.         mov     eax, [ebp+NTFS.newMftRecord]
  2456.         mov     [edi+fileRecordReference], eax
  2457. ; 6. Write directory node
  2458.         mov     eax, [ebp+NTFS.nodeLastRead]
  2459.         mov     [ebp+NTFS.ntfsLastRead], eax
  2460.         mov     eax, [ebp+NTFS.cur_index_buf]
  2461.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  2462.         call    writeRecord
  2463.         mov     ebx, [ebp+NTFS.fileRealSize]
  2464. ntfsDone:
  2465.         mov     esi, [ebp+PARTITION.Disk]
  2466.         call    disk_sync
  2467.         call    ntfs_unlock
  2468.         xor     eax, eax
  2469.         ret
  2470.  
  2471. writeRecord:
  2472. ; make updateSequence and write to disk
  2473. ;   in:
  2474. ; [ebp+NTFS.ntfs_cur_buf] -> record
  2475. ; [ebp+NTFS.ntfsLastRead] = partition sector
  2476.         mov     esi, [ebp+NTFS.ntfs_cur_buf]
  2477.         mov     edi, esi
  2478.         movzx   ecx, word [esi+updateSequenceOffset]
  2479.         add     edi, ecx
  2480.         mov     ax, [edi]
  2481.         inc     ax
  2482.         stosw
  2483.         mov     cx, [esi+updateSequenceSize]
  2484.         dec     ecx
  2485.         push    ecx
  2486. @@:
  2487.         add     esi, 510
  2488.         movsw
  2489.         mov     [esi-2], ax
  2490.         dec     ecx
  2491.         jnz     @b
  2492.         mov     eax, [ebp+NTFS.ntfsLastRead]
  2493.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  2494.         pop     ecx
  2495.         xor     edx, edx
  2496.         jmp     fs_write64_sys
  2497.  
  2498. createMcbEntry:
  2499. ;   in:
  2500. ; [ebp+NTFS.fileDataStart] = position value
  2501. ; [ebp+NTFS.fileDataSize] = size value
  2502. ; edi -> destination
  2503. ; esi -> attribute header
  2504.         mov     eax, [ebp+NTFS.fileDataStart]
  2505.         xor     edx, edx
  2506.         shl     eax, 1
  2507.         jnc     @f
  2508.         not     eax
  2509. @@:
  2510.         inc     edx
  2511.         shr     eax, 8
  2512.         jnz     @b
  2513.         mov     eax, [ebp+NTFS.fileDataSize]
  2514.         shl     eax, 1
  2515.         xor     ecx, ecx
  2516. @@:
  2517.         inc     ecx
  2518.         shr     eax, 8
  2519.         jnz     @b
  2520.         lea     eax, [edi+edx+1]
  2521.         add     eax, ecx
  2522.         sub     eax, esi
  2523.         sub     eax, [esi+sizeWithHeader]
  2524.         jc      @f
  2525.         add     word [esi+sizeWithHeader], 8    ; extend attribute
  2526.         mov     esi, [ebp+NTFS.frs_buffer]
  2527.         mov     eax, [esi+recordRealSize]
  2528.         add     eax, 8
  2529.         cmp     [esi+recordAllocatedSize], eax
  2530.         jc      .end    ; no space in the record
  2531.         mov     [esi+recordRealSize], eax
  2532.         push    ecx edi
  2533.         add     esi, eax
  2534.         mov     ecx, esi
  2535.         sub     ecx, edi
  2536.         sub     ecx, 8
  2537.         shr     ecx, 2
  2538.         mov     edi, esi
  2539.         sub     edi, 4
  2540.         sub     esi, 12
  2541.         std
  2542.         rep movsd
  2543.         cld
  2544.         pop     edi ecx
  2545. @@:
  2546.         mov     eax, edx
  2547.         shl     eax, 4
  2548.         add     eax, ecx
  2549.         stosb
  2550.         lea     esi, [ebp+NTFS.fileDataSize]
  2551.         rep movsb
  2552.         lea     esi, [ebp+NTFS.fileDataStart]
  2553.         mov     ecx, edx
  2554.         rep movsb
  2555.         mov     [edi], cl
  2556. .end:
  2557.         ret
  2558.  
  2559. resizeAttribute:
  2560. ;   in:
  2561. ; [ebp+NTFS.frs_buffer] -> file record
  2562. ; [ebp+NTFS.ntfs_attr_offs] -> attribute
  2563. ; edx:eax = new size
  2564. ;   out:
  2565. ; [ebp+NTFS.fileDataSize] = clusters added (positive)
  2566. ; [ebp+NTFS.fileDataStart] = added block
  2567. ; CF=1 -> eax = error code
  2568.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  2569.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  2570.         mov     dword [ebp+NTFS.ntfs_attr_size+4], edx
  2571.         cmp     byte [esi+nonResidentFlag], 0
  2572.         jz      .resident
  2573.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2574.         shl     ecx, 9
  2575.         mov     [esi+attributeRealSize], eax
  2576.         mov     [esi+attributeRealSize+4], edx
  2577.         mov     [esi+initialDataSize], eax
  2578.         mov     [esi+initialDataSize+4], edx
  2579.         sub     eax, 1
  2580.         sbb     edx, 0
  2581.         jc      .makeResident
  2582.         div     ecx
  2583.         mov     edi, eax
  2584.         inc     eax
  2585.         mul     ecx
  2586.         mov     [esi+attributeAllocatedSize], eax
  2587.         mov     [esi+attributeAllocatedSize+4], edx
  2588.         mov     ecx, [esi+lastVCN]
  2589.         mov     [esi+lastVCN], edi
  2590.         movzx   eax, byte [esi+dataRunsOffset]
  2591.         sub     edi, ecx
  2592.         mov     [ebp+NTFS.fileDataSize], edi
  2593.         jz      .done
  2594.         jc      .shrinkAttribute
  2595. ; extend attribute
  2596.         xor     edi, edi
  2597.         add     esi, eax
  2598.         push    edi edi edi edi
  2599. @@:
  2600.         mov     edx, eax
  2601.         mov     eax, esi
  2602.         add     edi, [esp+8]
  2603.         call    ntfs_decode_mcb_entry
  2604.         jc      @b
  2605.         mov     [esp+4], edx
  2606.         mov     [esp+12], edi
  2607.         add     edi, [esp]
  2608.         push    edi
  2609.         shr     edi, 5
  2610.         shl     edi, 2
  2611.         push    eax
  2612.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  2613.         jz      @f
  2614.         cmp     edi, [ebp+NTFS.BitmapStart]
  2615.         jc      .err1
  2616. @@:
  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     [ebp+NTFS.fileDataSize], ecx
  2645.         mov     [ebp+NTFS.fileDataStart], eax
  2646. .writeBitmap:
  2647.         add     ecx, eax
  2648.         add     ecx, 4095
  2649.         shr     ecx, 3+9
  2650.         shr     eax, 3+9
  2651.         sub     ecx, eax
  2652.         mov     ebx, eax
  2653.         shl     ebx, 9
  2654.         add     eax, [ebp+NTFS.BitmapLocation]
  2655.         add     ebx, [ebp+NTFS.BitmapBuffer]
  2656.         xor     edx, edx
  2657.         call    fs_write64_app
  2658.         test    eax, eax
  2659.         jnz     @f
  2660. .done:
  2661.         ret
  2662.  
  2663. .err4:
  2664.         pop     eax
  2665. @@:
  2666.         movi    eax, ERROR_DEVICE
  2667.         stc
  2668.         ret
  2669.  
  2670. .err1:
  2671.         add     esp, 24
  2672.         stc
  2673. .err10:
  2674.         movi    eax, ERROR_DISK_FULL
  2675.         ret
  2676.  
  2677. .err2:
  2678.         movi    eax, ERROR_UNSUPPORTED_FS
  2679.         ret
  2680.  
  2681. .shrinkAttribute:
  2682.         add     ecx, edi
  2683.         inc     ecx
  2684.         add     esi, eax
  2685.         xor     edi, edi
  2686.         sub     esp, 20
  2687. @@:
  2688.         mov     [esp+16], esi
  2689.         call    ntfs_decode_mcb_entry
  2690.         jnc     .err3
  2691.         add     edi, [esp+8]
  2692.         sub     ecx, [esp]
  2693.         jnc     @b
  2694.         mov     ebx, ecx
  2695.         add     ecx, [esp]
  2696.         mov     eax, [esp+8]
  2697.         mov     [ebp+NTFS.fileDataSize], ecx
  2698.         mov     [ebp+NTFS.fileDataStart], eax
  2699.         push    edi
  2700.         add     edi, ecx
  2701.         neg     ebx
  2702.         call    ntfsSpaceFree
  2703.         pop     edi
  2704.         jc      .end
  2705. @@:
  2706.         call    ntfs_decode_mcb_entry
  2707.         jnc     .end
  2708.         cmp     dword[esp+8], 0
  2709.         jz      @b
  2710.         add     edi, [esp+8]
  2711.         mov     ebx, [esp]
  2712.         call    ntfsSpaceFree
  2713.         jnc     @b
  2714. .end:
  2715.         add     esp, 16
  2716.         pop     edi
  2717.         cmp     [ebp+NTFS.fileDataSize], 0
  2718.         jz      @f
  2719.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  2720.         call    createMcbEntry
  2721.         mov     [ebp+NTFS.fileDataSize], 0
  2722. @@:
  2723.         ret
  2724.  
  2725. .err3:
  2726.         movi    eax, ERROR_FS_FAIL
  2727.         add     esp, 20
  2728.         stc
  2729.         ret
  2730.  
  2731. .resident:
  2732.         test    edx, edx
  2733.         jnz     .nonResident
  2734.         cmp     eax, 8000h
  2735.         jnc     .nonResident
  2736.         add     ax, [esi+attributeOffset]
  2737.         sub     eax, [esi+sizeWithHeader]
  2738.         jc      @f
  2739.         mov     edi, [ebp+NTFS.frs_buffer]
  2740.         mov     ecx, eax
  2741.         add     ecx, [edi+recordRealSize]
  2742.         cmp     [edi+recordAllocatedSize], ecx
  2743.         jc      .nonResident
  2744.         add     eax, 7
  2745.         and     eax, not 7
  2746.         add     [edi+recordRealSize], eax
  2747.         add     edi, [edi+recordRealSize]
  2748.         add     [esi+sizeWithHeader], eax
  2749.         add     esi, [esi+sizeWithHeader]
  2750.         mov     ecx, edi
  2751.         sub     ecx, esi
  2752.         shr     ecx, 2
  2753.         sub     edi, 4
  2754.         mov     esi, edi
  2755.         sub     esi, eax
  2756.         std
  2757.         rep movsd
  2758.         mov     ecx, eax
  2759.         shr     ecx, 2
  2760.         xor     eax, eax
  2761.         rep stosd
  2762.         cld
  2763.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  2764. @@:
  2765.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  2766.         mov     [esi+sizeWithoutHeader], eax
  2767.         mov     [ebp+NTFS.fileDataSize], 0
  2768.         clc
  2769.         ret
  2770.  
  2771. .nonResident:   ; convert resident to non-resident
  2772.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  2773.         sub     eax, 1
  2774.         sbb     edx, 0
  2775.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2776.         shl     ecx, 9
  2777.         div     ecx
  2778.         inc     eax
  2779.         mov     [ebp+NTFS.fileDataSize], eax
  2780.         mov     edi, [ebp+NTFS.BitmapStart]
  2781.         push    ecx
  2782.         call    ntfsSpaceAlloc
  2783.         pop     ecx
  2784.         jc      .err10
  2785.         mov     [ebp+NTFS.fileDataStart], eax
  2786.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  2787.         xor     eax, eax
  2788.         xor     edx, edx
  2789. @@:
  2790.         add     eax, ecx
  2791.         inc     edx
  2792.         cmp     eax, [esi+sizeWithoutHeader]
  2793.         jc      @b
  2794.         push    edx
  2795.         push    eax
  2796.         stdcall kernel_alloc, eax
  2797.         mov     ecx, [esp]
  2798.         shr     ecx, 2
  2799.         mov     edi, eax
  2800.         mov     ebx, eax
  2801.         xor     eax, eax
  2802.         rep stosd
  2803.         mov     al, [esi+attributeOffset]
  2804.         mov     ecx, [esi+sizeWithoutHeader]
  2805.         add     esi, eax
  2806.         mov     edi, ebx
  2807.         rep movsb
  2808.         mov     eax, [ebp+NTFS.fileDataStart]
  2809.         mul     [ebp+NTFS.sectors_per_cluster]
  2810.         pop     ecx
  2811.         shr     ecx, 9
  2812.         call    fs_write64_app
  2813.         push    ebx
  2814.         mov     ebx, eax
  2815.         call    kernel_free
  2816.         test    ebx, ebx
  2817.         jnz     .err4
  2818.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  2819.         add     esi, [esi+sizeWithHeader]
  2820.         mov     ecx, [ebp+NTFS.frs_buffer]
  2821.         add     ecx, [ecx+recordRealSize]
  2822.         sub     ecx, esi
  2823.         shr     ecx, 2
  2824.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  2825.         push    ecx
  2826.         rep movsd
  2827.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  2828.         add     edi, 16
  2829.         mov     cl, 6
  2830.         xor     eax, eax
  2831.         rep stosd
  2832.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  2833.         mov     eax, [ebp+NTFS.fileDataSize]
  2834.         dec     eax
  2835.         mov     [edi+lastVCN], eax
  2836.         inc     eax
  2837.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2838.         shl     ecx, 9
  2839.         mul     ecx
  2840.         mov     byte [edi+sizeWithHeader], 50h
  2841.         mov     byte [edi+nonResidentFlag], 1
  2842.         mov     byte [edi+dataRunsOffset], 40h
  2843.         mov     [edi+attributeAllocatedSize], eax
  2844.         mov     [edi+attributeAllocatedSize+4], edx
  2845.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  2846.         mov     edx, dword [ebp+NTFS.ntfs_attr_size+4]
  2847.         mov     [edi+attributeRealSize], eax
  2848.         mov     [edi+attributeRealSize+4], edx
  2849.         mov     [edi+initialDataSize], eax
  2850.         mov     [edi+initialDataSize+4], edx
  2851.         mov     esi, edi
  2852.         add     edi, 40h
  2853.         call    createMcbEntry
  2854.         mov     eax, edi
  2855.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  2856.         sub     eax, edi
  2857.         add     eax, 8
  2858.         and     eax, not 7
  2859.         mov     [edi+sizeWithHeader], eax
  2860.         pop     ecx
  2861.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf]
  2862.         add     edi, eax
  2863.         rep movsd
  2864.         mov     esi, [ebp+NTFS.frs_buffer]
  2865.         sub     edi, esi
  2866.         mov     [esi+recordRealSize], edi
  2867.         pop     edx
  2868.         mov     ecx, [ebp+NTFS.fileDataSize]
  2869.         sub     [ebp+NTFS.fileDataSize], edx
  2870.         mov     eax, [ebp+NTFS.fileDataStart]
  2871.         add     [ebp+NTFS.fileDataStart], edx
  2872.         jmp     .writeBitmap
  2873.  
  2874. .makeResident:  ; convert non-resident to empty resident
  2875.         movzx   eax, byte [esi+dataRunsOffset]
  2876.         mov     byte [esi+nonResidentFlag], 0
  2877.         mov     dword [esi+sizeWithoutHeader], 0
  2878.         mov     dword [esi+attributeOffset], 18h
  2879.         add     esi, eax
  2880.         xor     edi, edi
  2881.         sub     esp, 16
  2882. @@:
  2883.         call    ntfs_decode_mcb_entry
  2884.         jnc     @f
  2885.         cmp     dword[esp+8], 0
  2886.         jz      @b
  2887.         add     edi, [esp+8]
  2888.         mov     ebx, [esp]
  2889.         call    ntfsSpaceFree
  2890.         jnc     @b
  2891. @@:
  2892.         add     esp, 16
  2893.         mov     [ebp+NTFS.fileDataSize], 0
  2894.         ret
  2895.  
  2896. ntfsSpaceClean:
  2897. ; clean up to 16 Mb of disk space
  2898. ;   in:
  2899. ; [ebp+NTFS.fileDataStart] = block to clean
  2900. ; [ebp+NTFS.fileDataSize] = block size
  2901.         mov     eax, [ebp+NTFS.fileDataSize]
  2902.         test    eax, eax
  2903.         jz      @f
  2904.         mul     [ebp+NTFS.sectors_per_cluster]
  2905.         cmp     eax, 8001h
  2906.         jnc     @f
  2907.         push    eax
  2908.         shl     eax, 9
  2909.         stdcall kernel_alloc, eax
  2910.         pop     ecx
  2911.         test    eax, eax
  2912.         jz      @f
  2913.         push    ecx
  2914.         shl     ecx, 7
  2915.         mov     edi, eax
  2916.         mov     ebx, eax
  2917.         xor     eax, eax
  2918.         rep stosd
  2919.         mov     eax, [ebp+NTFS.fileDataStart]
  2920.         mul     [ebp+NTFS.sectors_per_cluster]
  2921.         mov     [ebp+NTFS.ntfsLastRead], eax
  2922.         pop     ecx
  2923.         call    fs_write64_app
  2924.         stdcall kernel_free, ebx
  2925. @@:
  2926.         ret
  2927.  
  2928. ntfsSpaceAlloc:
  2929. ; find and mark block of free space in bitmap buffer
  2930. ;   in:
  2931. ; edi = offset in bitmap to start search from
  2932. ; [ebp+NTFS.fileDataSize] = block size in clusters
  2933. ;   out:
  2934. ; eax = allocated block starting cluster
  2935. ; CF=1 -> disk full
  2936.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  2937.         add     edi, ecx
  2938.         add     ecx, [ebp+NTFS.BitmapSize]
  2939.         sub     ecx, edi
  2940.         jnc     @f
  2941.         call    bitmapBuffering
  2942.         shl     ecx, 2
  2943. @@:
  2944.         shr     ecx, 2
  2945.         mov     eax, [ebp+NTFS.fileDataSize]
  2946.         shr     eax, 5
  2947.         jz      .small
  2948.         push    eax         ; bitmap dwords
  2949. .start:
  2950.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  2951.         add     ecx, [ebp+NTFS.BitmapSize]
  2952.         sub     ecx, edi
  2953.         shr     ecx, 2
  2954. @@:
  2955.         xor     eax, eax
  2956.         repnz scasd         ; search for empty dword
  2957.         jz      @f
  2958.         call    bitmapBuffering
  2959.         jmp     @b
  2960. @@:
  2961.         cmp     ecx, [esp]
  2962.         jnc     @f
  2963.         call    bitmapBuffering
  2964.         jmp     @b
  2965. @@:
  2966.         sub     edi, 4
  2967.         mov     ecx, [esp]
  2968.         mov     esi, edi
  2969.         xor     eax, eax
  2970.         repz scasd          ; check following dwords
  2971.         jnz     .start
  2972.         sub     esi, 4
  2973.         mov     eax, [esi]
  2974.         xor     edx, edx
  2975.         bsr     edx, eax
  2976.         inc     edx
  2977.         push    edx         ; starting bit
  2978.         push    esi         ; starting dword
  2979.         add     esi, 4
  2980.         neg     edx
  2981.         add     edx, 32
  2982.         mov     eax, [ebp+NTFS.fileDataSize]
  2983.         sub     eax, edx
  2984.         mov     edx, eax
  2985.         shr     eax, 5
  2986.         shl     eax, 2
  2987.         add     esi, eax
  2988.         mov     eax, [esi]
  2989.         bsf     ecx, eax    ; check last dword
  2990.         jz      .done
  2991.         and     edx, 31
  2992.         cmp     ecx, edx
  2993.         jnc     .done
  2994.         add     esp, 8
  2995.         jmp     .start
  2996.  
  2997. .small:     ; less than 32 clusters
  2998.         mov     eax, -1
  2999.         repz scasd          ; search for zero bits
  3000.         push    ecx
  3001.         test    ecx, ecx
  3002.         jnz     @f
  3003.         call    bitmapBuffering
  3004.         pop     eax
  3005.         jmp     .small
  3006. @@:
  3007.         sub     edi, 4
  3008.         mov     eax, [edi]
  3009.         not     eax
  3010. @@:
  3011.         bsf     ecx, eax    ; first 0
  3012.         jz      .again
  3013.         not     eax
  3014.         shr     eax, cl
  3015.         shl     eax, cl
  3016.         bsf     edx, eax    ; next 1
  3017.         jz      @f
  3018.         sub     edx, ecx
  3019.         cmp     edx, [ebp+NTFS.fileDataSize]
  3020.         jnc     .got        ; fits inside
  3021.         bsf     ecx, eax
  3022.         not     eax
  3023.         shr     eax, cl
  3024.         shl     eax, cl
  3025.         jmp     @b
  3026. @@:         ; next dword
  3027.         mov     eax, [edi+4]
  3028.         bsf     edx, eax
  3029.         jz      .got        ; empty
  3030.         add     edx, 32
  3031.         sub     edx, ecx
  3032.         cmp     edx, [ebp+NTFS.fileDataSize]
  3033.         jnc     .got        ; share between dwords
  3034. .again:
  3035.         add     edi, 4
  3036.         pop     ecx
  3037.         jmp     .small
  3038.  
  3039. .got:
  3040.         push    ecx         ; starting bit
  3041.         push    edi         ; starting dword
  3042. .done:      ; mark space
  3043.         mov     ecx, [esp+4]
  3044.         cmp     ecx, 32
  3045.         jc      @f
  3046.         xor     ecx, ecx
  3047.         add     dword [esp], 4
  3048.         mov     [esp+4], ecx
  3049. @@:
  3050.         mov     edi, [esp]
  3051.         xor     eax, eax
  3052.         dec     eax
  3053.         shr     eax, cl
  3054.         shl     eax, cl
  3055.         neg     ecx
  3056.         add     ecx, 32
  3057.         sub     ecx, [ebp+NTFS.fileDataSize]
  3058.         jc      @f
  3059.         shl     eax, cl     ; fits inside dword
  3060.         shr     eax, cl
  3061.         or      [edi], eax
  3062.         jmp     .end
  3063.  
  3064. @@:
  3065.         or      [edi], eax
  3066.         neg     ecx
  3067.         push    ecx
  3068.         shr     ecx, 5
  3069.         add     edi, 4
  3070.         xor     eax, eax
  3071.         dec     eax
  3072.         rep stosd
  3073.         pop     ecx
  3074.         and     ecx, 31
  3075.         shr     eax, cl
  3076.         shl     eax, cl
  3077.         not     eax
  3078.         or      [edi], eax
  3079. .end:
  3080.         pop     eax
  3081.         sub     eax, [ebp+NTFS.BitmapBuffer]
  3082.         shl     eax, 3
  3083.         pop     edx
  3084.         add     eax, edx
  3085.         pop     edx
  3086.         ret
  3087.  
  3088. ntfsSpaceFree:
  3089. ; free disk space
  3090. ;   in:
  3091. ; edi = starting cluster
  3092. ; ebx = size in clusters
  3093.         mov     eax, edi
  3094.         add     eax, ebx
  3095.         shr     eax, 3
  3096.         inc     eax
  3097.         cmp     eax, [ebp+NTFS.BitmapSize]
  3098.         jc      @f
  3099.         add     eax, [ebp+NTFS.BitmapBuffer]
  3100.         push    edi
  3101.         mov     edi, eax
  3102.         call    bitmapBuffering
  3103.         pop     edi
  3104. @@:
  3105.         push    edi
  3106.         mov     ecx, edi
  3107.         shr     edi, 5
  3108.         shl     edi, 2
  3109.         add     edi, [ebp+NTFS.BitmapBuffer]
  3110.         and     ecx, 31
  3111.         xor     eax, eax
  3112.         dec     eax
  3113.         shr     eax, cl
  3114.         shl     eax, cl
  3115.         neg     ecx
  3116.         add     ecx, 32
  3117.         sub     ecx, ebx
  3118.         jc      @f
  3119.         shl     eax, cl     ; fits inside dword
  3120.         shr     eax, cl
  3121.         not     eax
  3122.         and     [edi], eax
  3123.         jmp     .writeBitmap
  3124.  
  3125. @@:
  3126.         not     eax
  3127.         and     [edi], eax
  3128.         neg     ecx
  3129.         push    ecx
  3130.         shr     ecx, 5
  3131.         add     edi, 4
  3132.         xor     eax, eax
  3133.         rep stosd
  3134.         pop     ecx
  3135.         and     ecx, 31
  3136.         dec     eax
  3137.         shr     eax, cl
  3138.         shl     eax, cl
  3139.         and     [edi], eax
  3140. .writeBitmap:
  3141.         pop     eax
  3142.         mov     edi, eax
  3143.         lea     ecx, [eax+ebx+4095]
  3144.         shr     eax, 3+9
  3145.         shr     ecx, 3+9
  3146.         sub     ecx, eax
  3147.         mov     ebx, eax
  3148.         shl     ebx, 9
  3149.         add     eax, [ebp+NTFS.BitmapLocation]
  3150.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3151.         xor     edx, edx
  3152.         jmp     fs_write64_app
  3153.  
  3154. bitmapBuffering:
  3155. ; Extend BitmapBuffer and read next 32kb of bitmap
  3156. ; Warning: $Bitmap fragmentation is not foreseen
  3157. ; in: edi -> position in bitmap buffer
  3158. ; out: ecx = number of buffered dwords left
  3159.         push    ebx
  3160.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3161.         cmp     eax, [ebp+NTFS.BitmapSize]
  3162.         jz      .end
  3163.         stdcall alloc_pages, 8
  3164.         test    eax, eax
  3165.         jz      .end
  3166.         add     eax, 3
  3167.         mov     ebx, [ebp+NTFS.BitmapBuffer]
  3168.         add     ebx, [ebp+NTFS.BitmapSize]
  3169.         push    ebx
  3170.         mov     ecx, 8
  3171.         call    commit_pages
  3172.         mov     eax, [ebp+NTFS.BitmapSize]
  3173.         shr     eax, 9
  3174.         add     eax, [ebp+NTFS.BitmapLocation]
  3175.         pop     ebx
  3176.         mov     ecx, 64
  3177.         xor     edx, edx
  3178.         call    fs_read64_app
  3179.         test    eax, eax
  3180.         jnz     .err
  3181.         add     [ebp+NTFS.BitmapSize], 8000h
  3182.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3183.         cmp     eax, [ebp+NTFS.BitmapSize]
  3184.         jnc     @f
  3185.         mov     [ebp+NTFS.BitmapSize], eax
  3186. @@:
  3187.         pop     ebx
  3188.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3189.         add     ecx, [ebp+NTFS.BitmapSize]
  3190.         sub     ecx, edi
  3191.         jc      bitmapBuffering
  3192.         shr     ecx, 2
  3193.         ret
  3194.  
  3195. .err:
  3196.         mov     eax, [ebp+NTFS.BitmapBuffer]
  3197.         add     eax, [ebp+NTFS.BitmapSize]
  3198.         mov     ecx, 8
  3199.         call    release_pages
  3200. .end:
  3201.         pop     ebx
  3202.         pop     eax     ; ret
  3203.         pop     eax
  3204.         stc
  3205.         ret
  3206.  
  3207. ;----------------------------------------------------------------
  3208. ntfs_WriteFile:
  3209.         cmp     byte [esi], 0
  3210.         jnz     @f
  3211.         xor     ebx, ebx
  3212.         movi    eax, ERROR_ACCESS_DENIED
  3213.         ret
  3214. @@:
  3215.         call    ntfs_lock
  3216.         stdcall ntfs_find_lfn, [esp+4]
  3217.         jc      ntfsNotFound
  3218.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 16
  3219.         jc      ntfsDenied
  3220.         bt      dword [eax+fileFlags], 28
  3221.         jc      ntfsDenied
  3222.         cmp     [ebp+NTFS.ntfsFragmentCount], 1
  3223.         jnz     ntfsUnsupported     ; record fragmented
  3224. ; edit directory node
  3225.         mov     edi, [ebp+NTFS.cur_index_buf]
  3226.         cmp     dword [edi], 'INDX'
  3227.         jz      @f
  3228.         mov     esi, [ebp+NTFS.frs_buffer]
  3229.         mov     ecx, [esi+recordRealSize]
  3230.         shr     ecx, 2
  3231.         rep movsd
  3232.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  3233.         mov     cl, [esi+attributeOffset]
  3234.         sub     esi, [ebp+NTFS.frs_buffer]
  3235.         add     eax, ecx
  3236.         add     eax, esi
  3237. @@:
  3238.         mov     ecx, [ebx+4]
  3239.         mov     edx, [ebx+8]
  3240.         add     ecx, [ebx+12]
  3241.         adc     edx, 0
  3242.         mov     [eax+fileRealSize], ecx
  3243.         mov     [eax+fileRealSize+4], edx
  3244.         mov     eax, [ebp+NTFS.ntfsLastRead]
  3245.         mov     [ebp+NTFS.nodeLastRead], eax
  3246.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  3247.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  3248.         mov     [ebp+NTFS.ntfs_cur_size], 0
  3249.         call    ntfs_read_attr
  3250.         jc      ntfsFail
  3251.         mov     eax, ecx
  3252.         mov     ecx, [ebp+NTFS.frs_buffer]
  3253.         cmp     word [ecx+baseRecordReuse], 0
  3254.         jnz     ntfsUnsupported     ; auxiliary record
  3255.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  3256.         cmp     word [ecx+attributeFlags], 0
  3257.         jnz     ntfsUnsupported
  3258.         push    ebx
  3259.         cmp     byte [ecx+nonResidentFlag], 0
  3260.         jz      .resizeAttribute
  3261.         cmp     edx, [ecx+attributeRealSize+4]
  3262.         jc      .writeNode
  3263.         jnz     .resizeAttribute
  3264.         cmp     [ecx+attributeRealSize], eax
  3265.         jnc     .writeNode
  3266. .resizeAttribute:
  3267.         call    resizeAttribute
  3268.         jc      ntfsErrorPop
  3269.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  3270.         cmp     byte [ecx+nonResidentFlag], 1
  3271.         jz      @f
  3272.         mov     ebx, [esp]
  3273.         movzx   edi, byte [ecx+attributeOffset]
  3274.         add     edi, ecx
  3275.         add     edi, [ebx+4]
  3276.         mov     ecx, [ebx+12]
  3277.         mov     esi, [ebx+16]
  3278.         rep movsb
  3279. @@:
  3280.         mov     eax, [ebp+NTFS.frs_buffer]
  3281.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  3282.         call    writeRecord     ; file
  3283.         mov     ebx, [ebp+NTFS.frs_buffer]
  3284.         call    ntfs_restore_usa_frs
  3285. .writeNode:
  3286.         mov     eax, [ebp+NTFS.nodeLastRead]
  3287.         mov     [ebp+NTFS.ntfsLastRead], eax
  3288.         mov     eax, [ebp+NTFS.cur_index_buf]
  3289.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  3290.         call    writeRecord     ; directory
  3291.         pop     ebx
  3292.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  3293.         cmp     byte [ecx+nonResidentFlag], 0
  3294.         jz      .done
  3295.         mov     ecx, [ebx+12]
  3296.         test    ecx, ecx
  3297.         jz      .done
  3298.         mov     eax, [ebx+4]
  3299.         mov     edx, [ebx+8]
  3300.         mov     esi, [ebx+16]
  3301.         shrd    eax, edx, 9
  3302.         test    dword[ebx+4], 1FFh
  3303.         jz      .aligned
  3304.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  3305.         mov     [ebp+NTFS.ntfs_cur_size], 1
  3306.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  3307.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  3308.         call    ntfs_read_attr.continue
  3309.         jc      ntfsDevice
  3310.         mov     eax, [ebx+4]
  3311.         and     eax, 1FFh
  3312.         add     edi, eax
  3313.         sub     eax, [ebp+NTFS.ntfs_cur_read]
  3314.         neg     eax
  3315.         push    ecx
  3316.         cmp     ecx, eax
  3317.         jb      @f
  3318.         mov     ecx, eax
  3319. @@:
  3320.         sub     [esp], ecx
  3321.         rep movsb
  3322.         push    ebx
  3323.         mov     eax, [ebp+NTFS.ntfsLastRead]
  3324.         lea     ebx, [ebp+NTFS.ntfs_bitmap_buf]
  3325.         mov     ecx, 1
  3326.         xor     edx, edx
  3327.         call    fs_write64_app
  3328.         pop     ebx
  3329.         pop     ecx
  3330.         test    ecx, ecx
  3331.         jz      .done
  3332.         mov     eax, [ebx+4]
  3333.         mov     edx, [ebx+8]
  3334.         shrd    eax, edx, 9
  3335.         inc     eax
  3336. .aligned:
  3337.         push    ecx
  3338.         shr     ecx, 9
  3339.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  3340.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  3341.         mov     [ebp+NTFS.ntfs_cur_buf], esi
  3342.         add     eax, ecx
  3343.         push    eax
  3344.         mov     [ebp+NTFS.ntfsWriteAttr], 1
  3345.         call    ntfs_read_attr.continue
  3346.         mov     [ebp+NTFS.ntfsWriteAttr], 0
  3347.         pop     [ebp+NTFS.ntfs_cur_offs]
  3348.         pop     ecx
  3349.         jc      ntfsDevice
  3350.         and     ecx, 1FFh
  3351.         jz      .done
  3352.         add     esi, [ebp+NTFS.ntfs_cur_read]
  3353.         mov     [ebp+NTFS.ntfs_cur_size], 1
  3354.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  3355.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  3356.         call    ntfs_read_attr.continue
  3357.         jc      ntfsDevice
  3358.         rep movsb
  3359.         push    ebx
  3360.         mov     eax, [ebp+NTFS.ntfsLastRead]
  3361.         lea     ebx, [ebp+NTFS.ntfs_bitmap_buf]
  3362.         mov     ecx, 1
  3363.         xor     edx, edx
  3364.         call    fs_write64_app
  3365.         pop     ebx
  3366. .done:
  3367.         mov     ebx, [ebx+12]
  3368.         jmp     ntfsDone
  3369.  
  3370. ;----------------------------------------------------------------
  3371. ntfs_Delete:
  3372.         cmp     byte [esi], 0
  3373.         jnz     @f
  3374.         xor     ebx, ebx
  3375.         movi    eax, ERROR_ACCESS_DENIED
  3376.         ret
  3377. @@:
  3378.         call    ntfs_lock
  3379.         stdcall ntfs_find_lfn, [esp+4]
  3380.         jc      ntfsNotFound
  3381.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 16
  3382.         jc      ntfsDenied
  3383.         cmp     [ebp+NTFS.ntfsFragmentCount], 1
  3384.         jnz     ntfsUnsupported     ; record fragmented
  3385.         test    byte [eax+indexFlags], 1
  3386.         jnz     ntfsUnsupported     ; index has a subnode
  3387.         mov     edx, [ebp+NTFS.ntfs_cur_iRecord]
  3388.         shr     edx, 3
  3389.         cmp     edx, [ebp+NTFS.mftBitmapSize]
  3390.         jnc     ntfsUnsupported
  3391. ; delete index from the node
  3392.         movzx   edx, word [eax+indexAllocatedSize]
  3393.         mov     ecx, [eax+fileRecordReference]
  3394.         cmp     [eax+edx+fileRecordReference], ecx
  3395.         jnz     @f
  3396.         add     dx, [eax+edx+indexAllocatedSize]
  3397. @@:
  3398.         mov     edi, [ebp+NTFS.cur_index_buf]
  3399.         cmp     dword [edi], 'INDX'
  3400.         jz      .indexRecord
  3401.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  3402.         mov     ecx, [esi+recordRealSize]
  3403.         shr     ecx, 2
  3404.         rep movsd
  3405.         mov     esi, [ebp+NTFS.cur_index_buf]
  3406.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  3407.         sub     edi, [ebp+NTFS.frs_buffer]
  3408.         add     edi, esi
  3409.         sub     [edi+sizeWithHeader], edx
  3410.         sub     [edi+sizeWithoutHeader], edx
  3411.         mov     cl, [edi+attributeOffset]
  3412.         add     edi, ecx
  3413.         sub     [edi+16+nodeRealSize], edx
  3414.         sub     [edi+16+nodeAllocatedSize], edx
  3415.         sub     eax, esi
  3416.         add     eax, edi
  3417.         sub     [esi+recordRealSize], edx
  3418.         mov     ecx, [esi+recordRealSize]
  3419.         jmp     @f
  3420.  
  3421. .indexRecord:
  3422.         sub     [edi+28], edx
  3423.         mov     ecx, [edi+28]
  3424.         add     ecx, 24
  3425. @@:
  3426.         add     ecx, [ebp+NTFS.cur_index_buf]
  3427.         sub     ecx, eax
  3428.         shr     ecx, 2
  3429.         mov     esi, eax
  3430.         add     esi, edx
  3431.         mov     edi, eax
  3432.         rep movsd
  3433.         mov     eax, [ebp+NTFS.ntfsLastRead]
  3434.         mov     [ebp+NTFS.nodeLastRead], eax
  3435. ; examine file record
  3436.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  3437.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  3438.         mov     [ebp+NTFS.ntfs_cur_size], 0
  3439.         call    ntfs_read_attr
  3440.         jc      .folder
  3441.         mov     esi, [ebp+NTFS.frs_buffer]
  3442.         cmp     word [esi+baseRecordReuse], 0
  3443.         jnz     ntfsUnsupported     ; auxiliary record
  3444.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  3445.         cmp     byte [esi+nonResidentFlag], 0
  3446.         jz      .writeBitmapMFT
  3447.         movzx   eax, byte [esi+dataRunsOffset]
  3448.         add     esi, eax
  3449.         xor     edi, edi
  3450.         sub     esp, 16
  3451. @@:         ; "delete" file data
  3452.         call    ntfs_decode_mcb_entry
  3453.         jnc     @f
  3454.         cmp     dword[esp+8], 0
  3455.         jz      @b
  3456.         add     edi, [esp+8]
  3457.         mov     ebx, [esp]
  3458.         call    ntfsSpaceFree
  3459.         jnc     @b
  3460. @@:
  3461.         add     esp, 16
  3462.         jmp     .writeBitmapMFT
  3463.  
  3464. .folder:    ; empty?
  3465.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf]
  3466.         mov     [ebp+NTFS.ntfs_cur_buf], esi
  3467.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90
  3468.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  3469.         mov     [ebp+NTFS.ntfs_cur_size], 1
  3470.         call    ntfs_read_attr
  3471.         cmp     [ebp+NTFS.ntfs_cur_read], 48
  3472.         jnz     ntfsDenied
  3473.         test    byte [esi+32+indexFlags], 1
  3474.         jnz     ntfsDenied
  3475. .writeBitmapMFT:    ; "delete" file record
  3476.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  3477.         mov     ecx, eax
  3478.         shr     eax, 3
  3479.         and     ecx, 7
  3480.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  3481.         btr     [edi+eax], ecx
  3482.         shr     eax, 9
  3483.         mov     ebx, eax
  3484.         shl     ebx, 9
  3485.         add     eax, [ebp+NTFS.mftBitmapLocation]
  3486.         add     ebx, edi
  3487.         mov     ecx, 1
  3488.         xor     edx, edx
  3489.         call    fs_write64_sys
  3490.         mov     esi, [ebp+NTFS.frs_buffer]
  3491.         mov     [ebp+NTFS.ntfs_cur_buf], esi
  3492.         mov     byte [esi+recordFlags], 0
  3493.         call    writeRecord
  3494. ; write directory node
  3495.         mov     eax, [ebp+NTFS.nodeLastRead]
  3496.         mov     [ebp+NTFS.ntfsLastRead], eax
  3497.         mov     eax, [ebp+NTFS.cur_index_buf]
  3498.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  3499.         call    writeRecord
  3500.         jmp     ntfsDone
  3501.  
  3502. ;----------------------------------------------------------------
  3503. ntfs_SetFileEnd:
  3504.         cmp     byte [esi], 0
  3505.         jnz     @f
  3506.         xor     ebx, ebx
  3507.         movi    eax, ERROR_ACCESS_DENIED
  3508.         ret
  3509. @@:
  3510.         call    ntfs_lock
  3511.         stdcall ntfs_find_lfn, [esp+4]
  3512.         jc      ntfsNotFound
  3513.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 16
  3514.         jc      ntfsDenied
  3515.         bt      dword [eax+fileFlags], 28
  3516.         jc      ntfsDenied
  3517.         cmp     [ebp+NTFS.ntfsFragmentCount], 1
  3518.         jnz     ntfsUnsupported     ; record fragmented
  3519. ; edit directory node
  3520.         mov     edi, [ebp+NTFS.cur_index_buf]
  3521.         cmp     dword [edi], 'INDX'
  3522.         jz      @f
  3523.         mov     esi, [ebp+NTFS.frs_buffer]
  3524.         mov     ecx, [esi+recordRealSize]
  3525.         shr     ecx, 2
  3526.         rep movsd
  3527.         mov     esi, [ebp+NTFS.ntfs_attr_offs]
  3528.         mov     cl, [esi+attributeOffset]
  3529.         sub     esi, [ebp+NTFS.frs_buffer]
  3530.         add     eax, ecx
  3531.         add     eax, esi
  3532. @@:
  3533.         mov     ecx, [ebx+4]
  3534.         mov     edx, [ebx+8]
  3535.         mov     [eax+fileRealSize], ecx
  3536.         mov     [eax+fileRealSize+4], edx
  3537.         mov     eax, [ebp+NTFS.ntfsLastRead]
  3538.         mov     [ebp+NTFS.nodeLastRead], eax
  3539.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  3540.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  3541.         mov     [ebp+NTFS.ntfs_cur_size], 0
  3542.         call    ntfs_read_attr
  3543.         jc      ntfsFail
  3544.         mov     eax, ecx
  3545.         mov     ecx, [ebp+NTFS.frs_buffer]
  3546.         cmp     word [ecx+baseRecordReuse], 0
  3547.         jnz     ntfsUnsupported     ; auxiliary record
  3548.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  3549.         cmp     word [ecx+attributeFlags], 0
  3550.         jnz     ntfsUnsupported
  3551.         cmp     byte [ecx+nonResidentFlag], 0
  3552.         jz      .resizeAttribute
  3553.         cmp     [ecx+attributeRealSize+4], edx
  3554.         jnz     .resizeAttribute
  3555.         cmp     [ecx+attributeRealSize], eax
  3556.         jnc     .resizeAttribute
  3557.         mov     eax, [ecx+attributeRealSize]
  3558.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3559.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  3560.         shl     ecx, 9
  3561.         div     ecx
  3562.         test    edx, edx
  3563.         jz      .aligned
  3564.         push    edx
  3565.         push    ecx
  3566.         mul     [ebp+NTFS.sectors_per_cluster]
  3567.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  3568.         stdcall kernel_alloc, ecx
  3569.         pop     ecx
  3570.         pop     edi
  3571.         sub     ecx, edi
  3572.         add     edi, eax
  3573.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  3574.         push    [ebp+NTFS.ntfsLastRead]
  3575.         call    ntfs_read_attr.continue
  3576.         jc      @f
  3577.         xor     eax, eax
  3578.         rep stosb
  3579.         push    ebx
  3580.         mov     eax, [ebp+NTFS.ntfsLastRead]
  3581.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  3582.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3583.         xor     edx, edx
  3584.         call    fs_write64_app
  3585.         pop     ebx
  3586. @@:
  3587.         pop     [ebp+NTFS.ntfsLastRead]
  3588.         stdcall kernel_free, [ebp+NTFS.ntfs_cur_buf]
  3589. .aligned:
  3590.         mov     eax, [ebx+4]
  3591.         mov     edx, [ebx+8]
  3592. .resizeAttribute:
  3593.         call    resizeAttribute
  3594.         jc      ntfsError
  3595.         mov     eax, [ebp+NTFS.frs_buffer]
  3596.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  3597.         call    writeRecord     ; file
  3598.         mov     eax, [ebp+NTFS.nodeLastRead]
  3599.         mov     [ebp+NTFS.ntfsLastRead], eax
  3600.         mov     eax, [ebp+NTFS.cur_index_buf]
  3601.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  3602.         call    writeRecord     ; directory
  3603.         call    ntfsSpaceClean
  3604.         jmp     ntfsDone
  3605.  
  3606. ;----------------------------------------------------------------
  3607. ntfs_SetFileInfo:
  3608.         movi    eax, ERROR_UNSUPPORTED_FS
  3609.         ret
  3610.  
  3611. ;----------------------------------------------------------------
  3612. ntfs_GetFileInfo:
  3613.         cmp     byte [esi], 0
  3614.         jnz     @f
  3615.         movi    eax, ERROR_UNSUPPORTED_FS
  3616.         ret
  3617. @@:
  3618.         call    ntfs_lock
  3619.         stdcall ntfs_find_lfn, [esp+4]
  3620.         jnc     .found
  3621.         test    eax, eax
  3622.         jz      ntfsFail
  3623.         jmp     ntfsNotFound
  3624. .found:
  3625.         push    esi edi
  3626.         mov     esi, eax
  3627.         mov     edi, [ebx+16]
  3628.         xor     eax, eax
  3629.         call    ntfs_direntry_to_bdfe
  3630.         pop     edi esi
  3631.         call    ntfs_unlock
  3632.         xor     eax, eax
  3633.         ret
  3634.  
  3635. ntfsUnsupported:
  3636.         push    ERROR_UNSUPPORTED_FS
  3637.         jmp     ntfsOut
  3638. ntfsDevice:
  3639.         push    ERROR_DEVICE
  3640.         jmp     ntfsOut
  3641. ntfsNotFound:
  3642.         push    ERROR_FILE_NOT_FOUND
  3643.         jmp     ntfsOut
  3644. ntfsDenied:
  3645.         push    ERROR_ACCESS_DENIED
  3646.         jmp     ntfsOut
  3647. ntfsFail:
  3648.         push    ERROR_FS_FAIL
  3649.         jmp     ntfsOut
  3650. ntfsDiskFull:
  3651.         push    ERROR_DISK_FULL
  3652.         jmp     ntfsOut
  3653. ntfsErrorPop2:
  3654.         pop     ebx
  3655. ntfsErrorPop:
  3656.         pop     ebx
  3657. ntfsError:
  3658.         push    eax
  3659. ntfsOut:
  3660.         call    ntfs_unlock
  3661.         xor     ebx, ebx
  3662.         pop     eax
  3663.         ret
  3664.