Subversion Repositories Kolibri OS

Rev

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

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