Subversion Repositories Kolibri OS

Rev

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