Subversion Repositories Kolibri OS

Rev

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