Subversion Repositories Kolibri OS

Rev

Rev 6408 | Rev 6411 | 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: 6409 $
  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 -> index in the target node
  1179. ; [ebp+NTFS.indexPointer] -> index, that points the target subnode
  1180. ; [ebp+NTFS.indexRoot] -> attribute
  1181. ; [ebp+NTFS.cur_size] = index record size in sectors
  1182. ; [ebp+NTFS.cur_subnode_size] = index record size in clusters or sectors
  1183. ; [ebp+NTFS.rootLastRead] = directory fileRecord sector
  1184. ; CF=1 -> file not found, eax=0 -> error
  1185.         mov     [ebp+NTFS.cur_iRecord], 5   ; start from root directory
  1186. .doit2:
  1187.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1188.         and     [ebp+NTFS.cur_offs], 0
  1189.         mov     eax, [ebp+NTFS.cur_index_size]
  1190.         mov     [ebp+NTFS.cur_size], eax
  1191.         mov     eax, [ebp+NTFS.cur_index_buf]
  1192.         mov     [ebp+NTFS.cur_buf], eax
  1193.         call    ntfs_read_attr
  1194.         mov     eax, 0
  1195.         jc      .ret
  1196.         cmp     [ebp+NTFS.cur_read], 0x20
  1197.         jc      .ret
  1198.         pushad
  1199.         mov     esi, [ebp+NTFS.cur_index_buf]
  1200.         mov     eax, [esi+indexRecordSize]
  1201.         shr     eax, 9
  1202.         cmp     [ebp+NTFS.cur_index_size], eax
  1203.         jc      .realloc
  1204.         mov     [ebp+NTFS.cur_size], eax
  1205.         mov     al, [esi+indexRecordSizeClus]
  1206.         mov     [ebp+NTFS.cur_subnode_size], eax
  1207.         add     esi, rootNode
  1208.         mov     eax, [esi+nodeRealSize]
  1209.         add     eax, rootNode
  1210.         cmp     [ebp+NTFS.cur_read], eax
  1211.         jc      .err
  1212.         mov     edi, [esp+4]
  1213.         mov     eax, [ebp+NTFS.mftLastRead]
  1214.         mov     [ebp+NTFS.rootLastRead], eax
  1215.         mov     eax, [ebp+NTFS.attr_offs]
  1216.         mov     [ebp+NTFS.indexRoot], eax
  1217. ; edi -> name, esi -> current index node
  1218. .scanloop:
  1219.         add     esi, [esi+indexOffset]
  1220. .scanloopint:
  1221.         test    byte [esi+indexFlags], 2
  1222.         jnz     .subnode
  1223.         push    esi
  1224.         movzx   ecx, byte [esi+fileNameLength]
  1225.         add     esi, fileName
  1226.         push    edi
  1227. @@:
  1228.         lodsw
  1229.         call    unichar_toupper
  1230.         push    eax
  1231.         mov     al, [edi]
  1232.         inc     edi
  1233.         cmp     al, '/'
  1234.         jz      .slash
  1235.         call    char_toupper
  1236.         call    ansi2uni_char
  1237.         cmp     ax, [esp]
  1238.         pop     eax
  1239.         loopz   @b
  1240.         jz      .found
  1241.         pop     edi
  1242.         pop     esi
  1243.         jb      .subnode
  1244. .scanloopcont:
  1245.         movzx   eax, word [esi+indexAllocatedSize]
  1246.         add     esi, eax
  1247.         jmp     .scanloopint
  1248.  
  1249. .realloc:
  1250.         mov     edi, eax
  1251.         mov     eax, [esi+indexRecordSize]
  1252.         shl     eax, 1
  1253.         stdcall kernel_alloc, eax
  1254.         test    eax, eax
  1255.         jz      .err
  1256.         mov     edx, [ebp+NTFS.cur_index_buf]
  1257.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1258.         jc      @f
  1259.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1260. @@:
  1261.         mov     [ebp+NTFS.cur_index_buf], eax
  1262.         add     eax, [esi+indexRecordSize]
  1263.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1264.         mov     [ebp+NTFS.cur_index_size], edi
  1265.         stdcall kernel_free, edx
  1266.         popad
  1267.         jmp     .doit2
  1268.  
  1269. .notfound:
  1270.         mov     [esp+1Ch], esi
  1271. .err:
  1272.         popad
  1273.         stc
  1274. .ret:
  1275.         ret     4
  1276.  
  1277. .slash:
  1278.         pop     eax
  1279.         pop     edi
  1280.         pop     esi
  1281. .subnode:
  1282.         test    byte [esi+indexFlags], 1
  1283.         jz      .notfound
  1284.         movzx   eax, word [esi+indexAllocatedSize]
  1285.         mov     eax, [esi+eax-8]
  1286.         mov     edx, [ebp+NTFS.cur_size]
  1287.         push    edx
  1288.         cmp     edx, [ebp+NTFS.cur_subnode_size]
  1289.         jz      @f
  1290.         mul     [ebp+NTFS.sectors_per_cluster]
  1291. @@:
  1292.         mov     [ebp+NTFS.indexPointer], esi
  1293.         mov     esi, [ebp+NTFS.cur_index_buf]
  1294.         xchg    [ebp+NTFS.secondIndexBuffer], esi
  1295.         mov     [ebp+NTFS.cur_index_buf], esi
  1296.         mov     [ebp+NTFS.cur_buf], esi
  1297.         mov     [ebp+NTFS.cur_attr], 0xA0   ; $INDEX_ALLOCATION
  1298.         mov     [ebp+NTFS.cur_offs], eax
  1299.         call    ntfs_read_attr.newAttribute
  1300.         pop     eax
  1301.         mov     [ebp+NTFS.cur_size], eax
  1302.         shl     eax, 9
  1303.         cmp     [ebp+NTFS.cur_read], eax
  1304.         jnz     .err
  1305.         cmp     dword [esi], 'INDX'
  1306.         jnz     .err
  1307.         mov     ebx, esi
  1308.         call    ntfs_restore_usa
  1309.         jc      .err
  1310.         add     esi, recordNode
  1311.         jmp     .scanloop
  1312.  
  1313. .found:
  1314.         cmp     byte [edi], 0
  1315.         jz      .done
  1316.         cmp     byte [edi], '/'
  1317.         jz      .next
  1318.         pop     edi
  1319.         pop     esi
  1320.         jmp     .scanloopcont
  1321.  
  1322. .done:
  1323. .next:
  1324.         pop     esi
  1325.         pop     esi
  1326.         mov     eax, [esi]
  1327.         mov     [ebp+NTFS.cur_iRecord], eax
  1328.         mov     [esp+1Ch], esi
  1329.         mov     [esp+4], edi
  1330.         popad
  1331.         inc     esi
  1332.         cmp     byte [esi-1], 0
  1333.         jnz     .doit2
  1334.         cmp     dword [esp+4], 0
  1335.         jz      .ret
  1336.         mov     esi, [esp+4]
  1337.         mov     dword [esp+4], 0
  1338.         jmp     .doit2
  1339.  
  1340. ;----------------------------------------------------------------
  1341. ntfs_ReadFile:
  1342.         cmp     byte [esi], 0
  1343.         jnz     @f
  1344.         or      ebx, -1
  1345.         movi    eax, ERROR_ACCESS_DENIED
  1346.         ret
  1347.  
  1348. @@:
  1349.         call    ntfs_lock
  1350.         stdcall ntfs_find_lfn, [esp+4]
  1351.         jnc     .found
  1352.         call    ntfs_unlock
  1353.         or      ebx, -1
  1354.         movi    eax, ERROR_FILE_NOT_FOUND
  1355.         ret
  1356.  
  1357. .found:
  1358.         mov     [ebp+NTFS.cur_attr], 0x80   ; $DATA
  1359.         and     [ebp+NTFS.cur_offs], 0
  1360.         and     [ebp+NTFS.cur_size], 0
  1361.         call    ntfs_read_attr
  1362.         jnc     @f
  1363.         call    ntfs_unlock
  1364.         or      ebx, -1
  1365.         movi    eax, ERROR_ACCESS_DENIED
  1366.         ret
  1367.  
  1368. @@:
  1369.         pushad
  1370.         and     dword [esp+10h], 0
  1371.         xor     eax, eax
  1372.         cmp     dword [ebx+8], 0x200
  1373.         jb      @f
  1374. .eof0:
  1375.         popad
  1376.         xor     ebx, ebx
  1377. .eof:
  1378.         call    ntfs_unlock
  1379.         movi    eax, ERROR_END_OF_FILE
  1380.         ret
  1381.  
  1382. @@:
  1383.         mov     ecx, [ebx+12]
  1384.         mov     edx, [ebx+16]
  1385.         mov     eax, [ebx+4]
  1386.         test    eax, 0x1FF
  1387.         jz      .alignedstart
  1388.         push    edx
  1389.         mov     edx, [ebx+8]
  1390.         shrd    eax, edx, 9
  1391.         pop     edx
  1392.         mov     [ebp+NTFS.cur_offs], eax
  1393.         mov     [ebp+NTFS.cur_size], 1
  1394.         lea     eax, [ebp+NTFS.bitmap_buf]
  1395.         mov     [ebp+NTFS.cur_buf], eax
  1396.         call    ntfs_read_attr.continue
  1397.         mov     eax, [ebx+4]
  1398.         and     eax, 0x1FF
  1399.         lea     esi, [ebp+NTFS.bitmap_buf+eax]
  1400.         sub     eax, [ebp+NTFS.cur_read]
  1401.         jae     .eof0
  1402.         neg     eax
  1403.         push    ecx
  1404.         cmp     ecx, eax
  1405.         jb      @f
  1406.         mov     ecx, eax
  1407. @@:
  1408.         mov     [esp+10h+4], ecx
  1409.         mov     edi, edx
  1410.         rep movsb
  1411.         mov     edx, edi
  1412.         pop     ecx
  1413.         sub     ecx, [esp+10h]
  1414.         jnz     @f
  1415. .retok:
  1416.         popad
  1417.         call    ntfs_unlock
  1418.         xor     eax, eax
  1419.         ret
  1420.  
  1421. @@:
  1422.         cmp     [ebp+NTFS.cur_read], 0x200
  1423.         jz      .alignedstart
  1424. .eof_ebx:
  1425.         popad
  1426.         jmp     .eof
  1427.  
  1428. .alignedstart:
  1429.         mov     eax, [ebx+4]
  1430.         push    edx
  1431.         mov     edx, [ebx+8]
  1432.         add     eax, 511
  1433.         adc     edx, 0
  1434.         shrd    eax, edx, 9
  1435.         pop     edx
  1436.         mov     [ebp+NTFS.cur_offs], eax
  1437.         mov     [ebp+NTFS.cur_buf], edx
  1438.         mov     eax, ecx
  1439.         shr     eax, 9
  1440.         mov     [ebp+NTFS.cur_size], eax
  1441.         add     eax, [ebp+NTFS.cur_offs]
  1442.         push    eax
  1443.         call    ntfs_read_attr.continue
  1444.         pop     [ebp+NTFS.cur_offs]
  1445.         mov     eax, [ebp+NTFS.cur_read]
  1446.         add     [esp+10h], eax
  1447.         mov     eax, ecx
  1448.         and     eax, not 0x1FF
  1449.         cmp     [ebp+NTFS.cur_read], eax
  1450.         jnz     .eof_ebx
  1451.         and     ecx, 0x1FF
  1452.         jz      .retok
  1453.         add     edx, [ebp+NTFS.cur_read]
  1454.         mov     [ebp+NTFS.cur_size], 1
  1455.         lea     eax, [ebp+NTFS.bitmap_buf]
  1456.         mov     [ebp+NTFS.cur_buf], eax
  1457.         call    ntfs_read_attr.continue
  1458.         cmp     [ebp+NTFS.cur_read], ecx
  1459.         jb      @f
  1460.         mov     [ebp+NTFS.cur_read], ecx
  1461. @@:
  1462.         xchg    ecx, [ebp+NTFS.cur_read]
  1463.         push    ecx
  1464.         mov     edi, edx
  1465.         lea     esi, [ebp+NTFS.bitmap_buf]
  1466.         add     [esp+10h+4], ecx
  1467.         rep movsb
  1468.         pop     ecx
  1469.         xor     eax, eax
  1470.         cmp     ecx, [ebp+NTFS.cur_read]
  1471.         jz      @f
  1472.         mov     al, ERROR_END_OF_FILE
  1473. @@:
  1474.         mov     [esp+1Ch], eax
  1475.         call    ntfs_unlock
  1476.         popad
  1477.         ret
  1478.  
  1479. ;----------------------------------------------------------------
  1480. ntfs_ReadFolder:
  1481.         call    ntfs_lock
  1482.         mov     [ebp+NTFS.cur_iRecord], 5   ; root directory
  1483.         cmp     byte [esi], 0
  1484.         jz      @f
  1485.         stdcall ntfs_find_lfn, [esp+4]
  1486.         jc      ntfsNotFound
  1487. @@:
  1488.         mov     [ebp+NTFS.cur_attr], 0x10   ; $STANDARD_INFORMATION
  1489.         and     [ebp+NTFS.cur_offs], 0
  1490.         mov     [ebp+NTFS.cur_size], 1
  1491.         lea     eax, [ebp+NTFS.bitmap_buf]
  1492.         mov     [ebp+NTFS.cur_buf], eax
  1493.         call    ntfs_read_attr
  1494.         jc      ntfsFail
  1495.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1496. .doit:
  1497.         mov     eax, [ebp+NTFS.cur_index_size]
  1498.         mov     [ebp+NTFS.cur_size], eax
  1499.         mov     eax, [ebp+NTFS.cur_index_buf]
  1500.         mov     [ebp+NTFS.cur_buf], eax
  1501.         call    ntfs_read_attr.newAttribute
  1502.         jc      ntfsFail
  1503.         cmp     [ebp+NTFS.cur_read], 0x20
  1504.         jc      ntfsFail
  1505.         mov     esi, [ebp+NTFS.cur_index_buf]
  1506.         mov     eax, [esi+indexRecordSize]
  1507.         shr     eax, 9
  1508.         cmp     [ebp+NTFS.cur_index_size], eax
  1509.         jc      .realloc
  1510.         mov     [ebp+NTFS.cur_subnode_size], eax
  1511.         add     esi, rootNode
  1512.         mov     eax, [esi+nodeRealSize]
  1513.         add     eax, rootNode
  1514.         cmp     [ebp+NTFS.cur_read], eax
  1515.         jc      ntfsFail
  1516.         mov     edi, [ebx+16]
  1517.         mov     ecx, [ebx+12]
  1518.         pushd   [ebx]
  1519.         pushd   [ebx+8]     ; read ANSI/UNICODE name
  1520.         push    edi
  1521.         mov     edx, esp
  1522.         mov     ebx, [ebx+4]
  1523. ; init header
  1524.         xor     eax, eax
  1525.         mov     [edi+8], eax
  1526.         mov     [edi+4], eax
  1527.         inc     eax
  1528.         mov     [edi], eax      ; version
  1529.         add     edi, 32
  1530. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1531. ; ecx = number of blocks to read
  1532. ; edx -> parameters block: dd <output>, dd <flags>
  1533.         cmp     [ebp+NTFS.cur_iRecord], 5
  1534.         jz      .skip_specials
  1535. ; dot and dotdot entries
  1536.         push    esi
  1537.         xor     esi, esi
  1538.         call    .add_special_entry
  1539.         inc     esi
  1540.         call    .add_special_entry
  1541.         pop     esi
  1542. .skip_specials:
  1543. ; at first, dump index root
  1544.         add     esi, [esi+indexOffset]
  1545. .dump_root:
  1546.         test    byte [esi+indexFlags], 2
  1547.         jnz     .dump_root_done
  1548.         call    .add_entry
  1549.         movzx   eax, word [esi+indexAllocatedSize]
  1550.         add     esi, eax
  1551.         jmp     .dump_root
  1552.  
  1553. .realloc:
  1554.         mov     edi, eax
  1555.         mov     eax, [esi+indexRecordSize]
  1556.         shl     eax, 1
  1557.         stdcall kernel_alloc, eax
  1558.         test    eax, eax
  1559.         jz      ntfsFail
  1560.         mov     edx, [ebp+NTFS.cur_index_buf]
  1561.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1562.         jc      @f
  1563.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1564. @@:
  1565.         mov     [ebp+NTFS.cur_index_buf], eax
  1566.         add     eax, [esi+indexRecordSize]
  1567.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1568.         mov     [ebp+NTFS.cur_index_size], edi
  1569.         stdcall kernel_free, edx
  1570.         jmp     .doit
  1571.  
  1572. .dump_root_done:
  1573. ; now dump all subnodes
  1574.         push    ecx edi
  1575.         lea     edi, [ebp+NTFS.bitmap_buf]
  1576.         mov     [ebp+NTFS.cur_buf], edi
  1577.         mov     ecx, 0x400/4
  1578.         xor     eax, eax
  1579.         rep stosd
  1580.         mov     [ebp+NTFS.cur_attr], 0xB0   ; $BITMAP
  1581.         and     [ebp+NTFS.cur_offs], 0
  1582.         mov     [ebp+NTFS.cur_size], 2
  1583.         call    ntfs_read_attr.newAttribute
  1584.         pop     edi ecx
  1585.         push    0       ; save offset in $BITMAP attribute
  1586.         and     [ebp+NTFS.cur_offs], 0
  1587. .dumploop:
  1588.         mov     [ebp+NTFS.cur_attr], 0xA0
  1589.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1590.         mov     [ebp+NTFS.cur_size], eax
  1591.         mov     esi, [ebp+NTFS.cur_index_buf]
  1592.         mov     [ebp+NTFS.cur_buf], esi
  1593.         mov     eax, [ebp+NTFS.cur_offs]
  1594.         push    eax
  1595.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1596.         mov     [ebp+NTFS.cur_offs], eax
  1597.         call    ntfs_read_attr.newAttribute
  1598.         pop     [ebp+NTFS.cur_offs]
  1599.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1600.         shl     eax, 9
  1601.         cmp     [ebp+NTFS.cur_read], eax
  1602.         jnz     .done
  1603.         push    eax
  1604.         mov     eax, [ebp+NTFS.cur_offs]
  1605.         and     eax, 0x400*8-1
  1606.         bt      dword [ebp+NTFS.bitmap_buf], eax
  1607.         pop     eax
  1608.         jnc     .dump_subnode_done
  1609.         cmp     dword [esi], 'INDX'
  1610.         jnz     .dump_subnode_done
  1611.         push    ebx
  1612.         mov     ebx, esi
  1613.         call    ntfs_restore_usa
  1614.         pop     ebx
  1615.         jc      .dump_subnode_done
  1616.         add     esi, recordNode
  1617.         add     esi, [esi+indexOffset]
  1618. .dump_subnode:
  1619.         test    byte [esi+indexFlags], 2
  1620.         jnz     .dump_subnode_done
  1621.         call    .add_entry
  1622.         movzx   eax, word [esi+indexAllocatedSize]
  1623.         add     esi, eax
  1624.         jmp     .dump_subnode
  1625.  
  1626. .dump_subnode_done:
  1627.         inc     [ebp+NTFS.cur_offs]
  1628.         test    [ebp+NTFS.cur_offs], 0x400*8-1
  1629.         jnz     .dumploop
  1630.         mov     [ebp+NTFS.cur_attr], 0xB0
  1631.         push    ecx edi
  1632.         lea     edi, [ebp+NTFS.bitmap_buf]
  1633.         mov     [ebp+NTFS.cur_buf], edi
  1634.         mov     ecx, 0x400/4
  1635.         xor     eax, eax
  1636.         rep stosd
  1637.         pop     edi ecx
  1638.         pop     eax
  1639.         push    [ebp+NTFS.cur_offs]
  1640.         inc     eax
  1641.         mov     [ebp+NTFS.cur_offs], eax
  1642.         mov     [ebp+NTFS.cur_size], 2
  1643.         push    eax
  1644.         call    ntfs_read_attr.newAttribute
  1645.         pop     eax
  1646.         pop     [ebp+NTFS.cur_offs]
  1647.         push    eax
  1648.         jmp     .dumploop
  1649.  
  1650. .done:
  1651.         pop     eax
  1652.         pop     eax
  1653.         mov     ebx, [eax+4]
  1654.         pop     eax
  1655.         pop     eax
  1656.         test    eax, eax
  1657.         jz      .ret
  1658.         xor     eax, eax
  1659.         dec     ecx
  1660.         js      @f
  1661.         mov     al, ERROR_END_OF_FILE
  1662. @@:
  1663.         push    eax
  1664.         call    ntfs_unlock
  1665.         pop     eax
  1666.         ret
  1667.  
  1668. .add_special_entry:
  1669.         mov     eax, [edx]
  1670.         inc     dword [eax+8]   ; new file found
  1671.         dec     ebx
  1672.         jns     .ret
  1673.         dec     ecx
  1674.         js      .ret
  1675.         inc     dword [eax+4]   ; new file block copied
  1676.         mov     eax, [edx+4]
  1677.         mov     [edi+4], eax
  1678.         mov     eax, 0x10
  1679.         stosd
  1680.         scasd
  1681.         push    edx
  1682.         mov     eax, dword [ebp+NTFS.bitmap_buf]
  1683.         mov     edx, dword [ebp+NTFS.bitmap_buf+4]
  1684.         call    ntfs_datetime_to_bdfe
  1685.         mov     eax, dword [ebp+NTFS.bitmap_buf+0x18]
  1686.         mov     edx, dword [ebp+NTFS.bitmap_buf+0x1C]
  1687.         call    ntfs_datetime_to_bdfe
  1688.         mov     eax, dword [ebp+NTFS.bitmap_buf+8]
  1689.         mov     edx, dword [ebp+NTFS.bitmap_buf+0xC]
  1690.         call    ntfs_datetime_to_bdfe
  1691.         pop     edx
  1692.         xor     eax, eax
  1693.         stosd
  1694.         stosd
  1695.         mov     al, '.'
  1696.         push    edi ecx
  1697.         lea     ecx, [esi+1]
  1698.         test    byte [edi-0x24], 1
  1699.         jz      @f
  1700.         rep stosw
  1701.         pop     ecx
  1702.         xor     eax, eax
  1703.         stosw
  1704.         pop     edi
  1705.         add     edi, 520
  1706.         ret
  1707.  
  1708. @@:
  1709.         rep stosb
  1710.         pop     ecx
  1711.         xor     eax, eax
  1712.         stosb
  1713.         pop     edi
  1714.         add     edi, 264
  1715. .ret:
  1716.         ret
  1717.  
  1718. .add_entry:
  1719. ; do not return DOS 8.3 names
  1720.         cmp     byte [esi+namespace], 2
  1721.         jz      .ret
  1722. ; do not return system files
  1723. ; ... note that there will be no bad effects if system files also were reported ...
  1724.         cmp     dword [esi+fileRecordReference], 0x10
  1725.         jb      .ret
  1726.         mov     eax, [edx]
  1727.         inc     dword [eax+8]   ; new file found
  1728.         dec     ebx
  1729.         jns     .ret
  1730.         dec     ecx
  1731.         js      .ret
  1732.         inc     dword [eax+4]   ; new file block copied
  1733.         mov     eax, [edx+4]    ; flags
  1734.         call    ntfs_direntry_to_bdfe
  1735.         push    ecx esi edi
  1736.         movzx   ecx, byte [esi+fileNameLength]
  1737.         add     esi, fileName
  1738.         test    byte [edi-0x24], 1
  1739.         jz      .ansi
  1740.         shr     ecx, 1
  1741.         rep movsd
  1742.         adc     ecx, ecx
  1743.         rep movsw
  1744.         and     word [edi], 0
  1745.         pop     edi
  1746.         add     edi, 520
  1747.         pop     esi ecx
  1748.         ret
  1749.  
  1750. .ansi:
  1751.         jecxz   .skip
  1752. @@:
  1753.         lodsw
  1754.         call    uni2ansi_char
  1755.         stosb
  1756.         loop    @b
  1757. .skip:
  1758.         xor     al, al
  1759.         stosb
  1760.         pop     edi
  1761.         add     edi, 264
  1762.         pop     esi ecx
  1763.         ret
  1764.  
  1765. ntfs_direntry_to_bdfe:
  1766.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1767.         mov     eax, [esi+fileFlags]
  1768.         test    eax, 0x10000000
  1769.         jz      @f
  1770.         and     eax, not 0x10000000
  1771.         or      al, 0x10
  1772. @@:
  1773.         stosd
  1774.         scasd
  1775.         push    edx
  1776.         mov     eax, [esi+fileCreated]
  1777.         mov     edx, [esi+fileCreated+4]
  1778.         call    ntfs_datetime_to_bdfe
  1779.         mov     eax, [esi+fileAccessed]
  1780.         mov     edx, [esi+fileAccessed+4]
  1781.         call    ntfs_datetime_to_bdfe
  1782.         mov     eax, [esi+fileModified]
  1783.         mov     edx, [esi+fileModified+4]
  1784.         call    ntfs_datetime_to_bdfe
  1785.         pop     edx
  1786.         mov     eax, [esi+fileRealSize]
  1787.         stosd
  1788.         mov     eax, [esi+fileRealSize+4]
  1789.         stosd
  1790.         ret
  1791.  
  1792. iglobal
  1793. months  db  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1794. months2 db  31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1795. endg
  1796.  
  1797. ntfs_datetime_to_bdfe:
  1798. ; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC
  1799.         push    ebx ecx
  1800.         mov     ebx, eax
  1801.         mov     eax, edx
  1802.         xor     edx, edx
  1803.         mov     ecx, 10000000
  1804.         div     ecx
  1805.         xchg    eax, ebx
  1806.         div     ecx
  1807. .forEXT:
  1808.         xchg    eax, ebx
  1809.         xor     edx, edx
  1810.         mov     ecx, 60
  1811.         div     ecx
  1812.         xchg    eax, ebx
  1813.         div     ecx
  1814.         mov     [edi], dl
  1815.         mov     edx, ebx
  1816. ; edx:eax = number of minutes
  1817.         div     ecx
  1818.         mov     [edi+1], dl
  1819. ; eax = number of hours
  1820.         xor     edx, edx
  1821.         mov     cl, 24
  1822.         div     ecx
  1823.         mov     [edi+2], dx
  1824. ; eax = number of days since January 1, 1601
  1825.         xor     edx, edx
  1826.         mov     cx, 365
  1827.         div     ecx
  1828.         mov     ebx, eax
  1829.         add     ebx, 1601
  1830.         shr     eax, 2
  1831.         sub     edx, eax
  1832.         mov     cl, 25
  1833.         div     cl
  1834.         xor     ah, ah
  1835.         add     edx, eax
  1836.         shr     eax, 2
  1837.         sub     edx, eax
  1838.         jns     @f
  1839.         dec     ebx
  1840.         add     edx, 365
  1841.         test    bl, 3
  1842.         jnz     @f
  1843.         inc     edx
  1844. @@:
  1845.         xor     eax, eax
  1846.         mov     ecx, months-1
  1847.         test    bl, 3
  1848.         jnz     @f
  1849.         add     ecx, 12
  1850. @@:
  1851.         inc     ecx
  1852.         inc     eax
  1853.         sub     dl, [ecx]
  1854.         jnc     @b
  1855.         dec     dh
  1856.         jns     @b
  1857.         add     dl, [ecx]
  1858.         inc     edx
  1859.         mov     [edi+4], dl
  1860.         mov     [edi+5], al
  1861.         mov     [edi+6], bx
  1862.         add     edi, 8
  1863.         pop     ecx ebx
  1864.         ret
  1865.  
  1866. .sec:
  1867.         push    ebx ecx
  1868.         mov     ebx, edx
  1869.         jmp     .forEXT
  1870.  
  1871. ;----------------------------------------------------------------
  1872. ntfs_CreateFolder:
  1873.         mov     [ebp+NTFS.bFolder], 1
  1874.         jmp     @f
  1875.  
  1876. ntfs_CreateFile:
  1877.         mov     [ebp+NTFS.bFolder], 0
  1878. @@:
  1879.         cmp     byte [esi], 0
  1880.         jnz     @f
  1881.         xor     ebx, ebx
  1882.         movi    eax, ERROR_ACCESS_DENIED
  1883.         ret
  1884.  
  1885. @@: ; 1. Search file
  1886.         call    ntfs_lock
  1887.         stdcall ntfs_find_lfn, [esp+4]
  1888.         jc      .notFound
  1889. ; found, rewrite
  1890.         cmp     [ebp+NTFS.cur_iRecord], 16
  1891.         jc      ntfsDenied
  1892.         cmp     [ebp+NTFS.bFolder], 1
  1893.         jz      .folder
  1894.         cmp     [ebp+NTFS.fragmentCount], 1
  1895.         jnz     ntfsUnsupported     ; record fragmented
  1896. ; edit directory node
  1897.         mov     edi, [ebp+NTFS.cur_index_buf]
  1898.         cmp     dword [edi], 'INDX'
  1899.         jz      @f
  1900.         mov     esi, [ebp+NTFS.frs_buffer]
  1901.         mov     ecx, [esi+recordRealSize]
  1902.         shr     ecx, 2
  1903.         rep movsd
  1904.         mov     esi, [ebp+NTFS.attr_offs]
  1905.         mov     cl, [esi+attributeOffset]
  1906.         sub     esi, [ebp+NTFS.frs_buffer]
  1907.         add     eax, ecx
  1908.         add     eax, esi
  1909. @@:
  1910.         mov     edx, [ebx+12]
  1911.         mov     [eax+fileRealSize], edx
  1912.         mov     dword [eax+fileRealSize+4], 0
  1913.         mov     eax, [ebp+NTFS.LastRead]
  1914.         mov     [ebp+NTFS.nodeLastRead], eax
  1915.         mov     [ebp+NTFS.cur_attr], 0x80
  1916.         mov     [ebp+NTFS.cur_offs], 0
  1917.         mov     [ebp+NTFS.cur_size], 0
  1918.         call    ntfs_read_attr
  1919.         jc      ntfsFail
  1920.         mov     ecx, [ebp+NTFS.frs_buffer]
  1921.         mov     eax, edx
  1922.         xor     edx, edx
  1923.         cmp     word [ecx+baseRecordReuse], 0
  1924.         jnz     ntfsUnsupported     ; auxiliary record
  1925.         mov     ecx, [ebp+NTFS.attr_offs]
  1926.         cmp     word [ecx+attributeFlags], 0
  1927.         jnz     ntfsUnsupported
  1928.         push    ebx
  1929.         cmp     byte [ecx+nonResidentFlag], 0
  1930.         jz      @f
  1931.         cmp     [ecx+attributeRealSize+4], edx
  1932.         jnz     @f
  1933.         cmp     [ecx+attributeRealSize], eax
  1934.         jz      ntfs_WriteFile.writeNode
  1935. @@:
  1936.         jmp     ntfs_WriteFile.resizeAttribute
  1937.  
  1938. .folder:
  1939.         bt      dword [eax+fileFlags], 28
  1940.         jnc     ntfsDenied
  1941.         push    0
  1942.         jmp     ntfsOut
  1943.  
  1944. .notFound:  ; create
  1945.         test    eax, eax
  1946.         jz      ntfsFail
  1947.         cmp     [ebp+NTFS.fragmentCount], 1
  1948.         jnz     ntfsUnsupported     ; record fragmented
  1949. ; 2. Prepare directory record
  1950.         mov     ecx, esi
  1951. @@:         ; count characters
  1952.         inc     ecx
  1953.         cmp     byte [ecx], '/'
  1954.         jz      ntfsNotFound    ; path folder not found
  1955.         cmp     byte [ecx], 0
  1956.         jnz     @b
  1957.         sub     ecx, esi
  1958.         push    ecx     ; name length
  1959.         shl     ecx, 1
  1960.         add     ecx, fileName+7
  1961.         and     ecx, not 7
  1962.         mov     edi, [ebp+NTFS.cur_index_buf]
  1963.         mov     edx, [ebx+12]
  1964.         mov     [ebp+NTFS.fileRealSize], edx
  1965.         mov     edx, [ebx+16]
  1966.         mov     [ebp+NTFS.fileDataBuffer], edx
  1967.         push    esi
  1968.         push    ecx     ; index length
  1969.         mov     edx, ecx
  1970.         cmp     dword [edi], 'INDX'
  1971.         jz      .indexRecord
  1972.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  1973.         mov     ecx, [esi+recordRealSize]
  1974.         add     edx, ecx
  1975.         cmp     [esi+recordAllocatedSize], edx
  1976.         jc      .growTree
  1977.         mov     [esi+recordRealSize], edx
  1978.         shr     ecx, 2
  1979.         rep movsd
  1980.         mov     edi, [ebp+NTFS.indexRoot]
  1981.         sub     edi, [ebp+NTFS.frs_buffer]
  1982.         add     edi, [ebp+NTFS.cur_index_buf]
  1983.         mov     esi, [esp]
  1984.         add     [edi+sizeWithHeader], esi
  1985.         add     [edi+sizeWithoutHeader], esi
  1986.         mov     cl, [edi+attributeOffset]
  1987.         add     edi, ecx
  1988.         add     [edi+rootNode+nodeRealSize], esi
  1989.         add     [edi+rootNode+nodeAllocatedSize], esi
  1990.         sub     eax, [ebp+NTFS.cur_index_buf]
  1991.         add     eax, edi
  1992.         mov     edi, [ebp+NTFS.cur_index_buf]
  1993.         jmp     .common
  1994.  
  1995. .growTree:
  1996.         xchg    [ebp+NTFS.secondIndexBuffer], edi
  1997.         mov     [ebp+NTFS.cur_index_buf], edi
  1998. ; create indexRecord
  1999.         mov     ecx, 10
  2000.         xor     eax, eax
  2001.         rep stosd
  2002.         mov     esi, [ebp+NTFS.indexRoot]
  2003.         mov     al, [esi+attributeOffset]
  2004.         add     esi, eax
  2005.         rdtsc
  2006.         stosw
  2007.         mov     eax, [esi+indexRecordSize]
  2008.         cmp     eax, [ebp+NTFS.frs_size]
  2009.         jc      .errorPop3
  2010.         shr     eax, 9
  2011.         inc     eax
  2012.         mov     edi, [ebp+NTFS.cur_index_buf]
  2013.         mov     dword[edi], 'INDX'
  2014.         mov     byte [edi+updateSequenceOffset], 28h
  2015.         mov     [edi+updateSequenceSize], al
  2016.         add     edi, recordNode
  2017.         shl     eax, 1
  2018.         add     eax, 28h-recordNode+7
  2019.         and     eax, not 7
  2020.         mov     [edi+indexOffset], eax
  2021.         mov     ecx, [esi+indexRecordSize]
  2022.         sub     ecx, recordNode
  2023.         mov     [edi+nodeAllocatedSize], ecx
  2024.         add     esi, rootNode
  2025.         push    esi
  2026.         mov     ecx, [esi+nodeRealSize]
  2027.         sub     ecx, [esi+indexOffset]
  2028.         add     eax, ecx
  2029.         mov     [edi+nodeRealSize], eax
  2030.         shr     ecx, 2
  2031.         add     esi, [esi+indexOffset]
  2032.         add     edi, [edi+indexOffset]
  2033.         rep movsd       ; copy root indexes
  2034. ; clear root node
  2035.         mov     cl, 10
  2036.         mov     edi, [esp]
  2037.         xor     eax, eax
  2038.         rep stosd
  2039.         pop     edi
  2040.         mov     byte [edi+indexOffset], 16
  2041.         mov     byte [edi+nodeRealSize], 28h
  2042.         mov     byte [edi+nodeAllocatedSize], 28h
  2043.         mov     byte [edi+nonLeafFlag], 1
  2044.         mov     byte [edi+16+indexAllocatedSize], 18h
  2045.         mov     byte [edi+16+indexFlags], 3
  2046.         mov     esi, [ebp+NTFS.indexRoot]
  2047.         add     edi, 28h
  2048.         mov     eax, edi
  2049.         sub     eax, esi
  2050.         mov     word [esi+sizeWithoutHeader], 38h
  2051.         xchg    [esi+sizeWithHeader], eax
  2052.         add     esi, eax
  2053.         mov     [ebp+NTFS.attr_offs], edi
  2054.         cmp     byte [esi], 0xA0
  2055.         jnz     @f
  2056.         cmp     dword [esi+attributeAllocatedSize], 0
  2057.         jz      @f
  2058.         mov     eax, [ebp+NTFS.frs_buffer]
  2059.         mov     ecx, eax
  2060.         add     ecx, [eax+recordRealSize]
  2061.         sub     ecx, esi
  2062.         shr     ecx, 2
  2063.         rep movsd
  2064.         sub     edi, eax
  2065.         mov     [eax+recordRealSize], edi
  2066.         call    .ntfsNodeAlloc
  2067.         jc      ntfsErrorPop3
  2068.         mov     eax, [ebp+NTFS.newRecord]
  2069.         mov     edi, [ebp+NTFS.cur_index_buf]
  2070.         mov     [edi+recordVCN], eax
  2071.         mov     edi, [ebp+NTFS.attr_offs]
  2072.         mov     [edi-8], eax
  2073.         jmp     .refresh
  2074.  
  2075. @@:
  2076.         mov     cl, 32
  2077.         xor     eax, eax
  2078.         rep stosd
  2079.         mov     eax, [ebp+NTFS.cur_subnode_size]
  2080.         cmp     eax, [ebp+NTFS.cur_size]
  2081.         jnz     @f
  2082.         mov     al, 1
  2083. @@:
  2084.         mov     [ebp+NTFS.fileDataSize], eax
  2085.         mov     edi, [ebp+NTFS.BitmapStart]
  2086.         call    ntfsSpaceAlloc
  2087.         movi    eax, ERROR_DISK_FULL
  2088.         jc      ntfsErrorPop3
  2089. ; create $IndexAllocation
  2090.         mov     edi, [ebp+NTFS.attr_offs]
  2091.         mov     byte [edi+attributeType], 0xA0
  2092.         mov     byte [edi+nonResidentFlag], 1
  2093.         mov     byte [edi+nameLength], 4
  2094.         mov     byte [edi+nameOffset], 40h
  2095.         mov     byte [edi+dataRunsOffset], 48h
  2096.         mov     byte [edi+sizeWithHeader], 50h
  2097.         mov     eax, [ebp+NTFS.fileDataSize]
  2098.         dec     eax
  2099.         mov     [edi+lastVCN], eax
  2100.         inc     eax
  2101.         mul     [ebp+NTFS.sectors_per_cluster]
  2102.         shl     eax, 9
  2103.         mov     [edi+attributeAllocatedSize], eax
  2104.         mov     [edi+attributeRealSize], eax
  2105.         mov     [edi+initialDataSize], eax
  2106.         mov     dword[edi+40h], 490024h     ; unicode $I30
  2107.         mov     dword[edi+40h+4], 300033h
  2108.         push    edi
  2109.         mov     esi, edi
  2110.         add     edi, 48h
  2111.         call    createMcbEntry
  2112.         mov     esi, [ebp+NTFS.frs_buffer]
  2113.         pop     edi
  2114.         mov     al, [esi+newAttributeID]
  2115.         mov     [edi+attributeID], al
  2116.         add     edi, 50h
  2117.         inc     eax
  2118. ; create $Bitmap
  2119.         mov     [edi+attributeID], al
  2120.         inc     eax
  2121.         mov     [esi+newAttributeID], al
  2122.         mov     byte [edi+attributeType], 0xB0
  2123.         mov     byte [edi+nameLength], 4
  2124.         mov     byte [edi+nameOffset], 18h
  2125.         mov     byte [edi+attributeOffset], 20h
  2126.         mov     byte [edi+sizeWithoutHeader], 8
  2127.         mov     byte [edi+sizeWithHeader], 28h
  2128.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2129.         mov     dword[edi+18h+4], 300033h
  2130.         mov     byte [edi+20h], 1
  2131.         mov     dword[edi+28h], -1
  2132.         add     edi, 30h
  2133.         sub     edi, esi
  2134.         mov     [esi+recordRealSize], edi
  2135.         mov     eax, [ebp+NTFS.fileDataStart]
  2136.         mul     [ebp+NTFS.sectors_per_cluster]
  2137.         mov     edx, eax
  2138.         jmp     @f
  2139.  
  2140. .refresh:
  2141.         mov     [ebp+NTFS.cur_size], 0
  2142.         call    ntfs_read_attr.continue
  2143.         movi    eax, ERROR_FS_FAIL
  2144.         jc      ntfsErrorPop3
  2145.         mov     edx, [ebp+NTFS.LastRead]
  2146. @@:
  2147.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2148.         call    writeRecord
  2149.         mov     ebx, [ebp+NTFS.frs_buffer]
  2150.         mov     edx, [ebp+NTFS.rootLastRead]
  2151.         call    writeRecord
  2152.         mov     esi, [esp+4]
  2153.         stdcall ntfs_find_lfn.doit2, 0
  2154.         test    eax, eax
  2155.         jz      .errorPop3
  2156.         mov     edi, [ebp+NTFS.cur_index_buf]
  2157.         mov     edx, [esp]
  2158. .indexRecord:
  2159.         add     edi, recordNode
  2160.         add     edx, [edi+nodeRealSize]
  2161.         cmp     [edi+nodeAllocatedSize], edx
  2162.         jc      .arborizeTree
  2163.         mov     [edi+nodeRealSize], edx
  2164.         jmp     .common
  2165.  
  2166. .errorPop3:
  2167.         add     esp, 12
  2168.         jmp     ntfsUnsupported
  2169.  
  2170. .ntfsNodeAlloc:
  2171. ; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
  2172. ;   out:
  2173. ; [ebp+NTFS.newRecord] = node VCN
  2174. ; [ebp+NTFS.cur_offs]
  2175. ; CF=1 -> eax = error code
  2176.         mov     esi, [ebp+NTFS.attr_offs]
  2177.         add     esi, [esi+sizeWithHeader]
  2178.         cmp     byte [esi], 0xB0
  2179.         jnz     .ret
  2180.         movzx   eax, byte [esi+attributeOffset]
  2181.         add     esi, eax
  2182.         mov     eax, [esi]
  2183.         not     eax
  2184.         bsf     eax, eax
  2185.         jz      .ret
  2186.         bts     [esi], eax
  2187.         mul     [ebp+NTFS.cur_subnode_size]
  2188.         mov     [ebp+NTFS.newRecord], eax
  2189.         mov     ecx, [ebp+NTFS.cur_size]
  2190.         cmp     ecx, [ebp+NTFS.cur_subnode_size]
  2191.         jz      @f
  2192.         mul     [ebp+NTFS.sectors_per_cluster]
  2193. @@:
  2194.         mov     [ebp+NTFS.cur_offs], eax
  2195.         add     eax, ecx
  2196.         shl     eax, 9
  2197.         mov     esi, [ebp+NTFS.attr_offs]
  2198.         cmp     [esi+attributeAllocatedSize], eax
  2199.         jnc     @f
  2200.         xor     edx, edx
  2201.         jmp     resizeAttribute
  2202.  
  2203. .ret:
  2204.         movi    eax, ERROR_UNSUPPORTED_FS
  2205.         stc
  2206. @@:
  2207.         ret
  2208.  
  2209. .arborizeTree:      ; find median index
  2210.         mov     ecx, [edi+nodeRealSize]
  2211.         sub     ecx, [edi+indexOffset]
  2212.         shr     ecx, 1
  2213.         add     edi, [edi+indexOffset]
  2214.         xor     eax, eax
  2215. @@:
  2216.         add     edi, eax
  2217.         mov     ax, [edi+indexAllocatedSize]
  2218.         sub     ecx, eax
  2219.         jnc     @b
  2220.         add     eax, 8
  2221.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2222.         cmp     dword [esi], 'INDX'
  2223.         jz      .errorPop3      ; move index to the branch node
  2224. ; move index to the root node
  2225.         mov     esi, [ebp+NTFS.frs_buffer]
  2226.         mov     ecx, eax
  2227.         add     ecx, 8
  2228.         add     ecx, [esi+recordRealSize]
  2229.         cmp     [esi+recordAllocatedSize], ecx
  2230.         jc      .errorPop3      ; tree grow required
  2231.         push    edi eax
  2232.         call    .ntfsNodeAlloc
  2233.         pop     ecx edi
  2234.         jc      ntfsErrorPop3
  2235.         push    edi
  2236.         mov     edi, [ebp+NTFS.indexRoot]
  2237.         mov     eax, ecx
  2238.         add     [ebp+NTFS.attr_offs], eax
  2239.         add     [edi+sizeWithHeader], eax
  2240.         add     [edi+sizeWithoutHeader], eax
  2241.         movzx   ecx, byte [edi+attributeOffset]
  2242.         add     ecx, edi
  2243.         add     [ecx+rootNode+nodeRealSize], eax
  2244.         add     [ecx+rootNode+nodeAllocatedSize], eax
  2245.         add     ecx, [ebp+NTFS.indexPointer]
  2246.         sub     ecx, [ebp+NTFS.secondIndexBuffer]
  2247.         mov     esi, [ebp+NTFS.frs_buffer]
  2248.         add     [esi+recordRealSize], eax
  2249.         add     esi, [esi+recordRealSize]
  2250.         mov     edi, esi
  2251.         sub     esi, eax
  2252.         neg     ecx
  2253.         add     ecx, esi
  2254.         shr     ecx, 2
  2255.         sub     esi, 4
  2256.         sub     edi, 4
  2257.         std
  2258.         rep movsd   ; make space
  2259.         mov     [edi], ecx
  2260.         mov     edi, esi
  2261.         add     edi, 4
  2262.         mov     esi, [esp]
  2263.         add     word [esi+indexAllocatedSize], 8
  2264.         mov     byte [esi+indexFlags], 1
  2265.         mov     ecx, eax
  2266.         sub     ecx, 8
  2267.         shr     ecx, 2
  2268.         cld
  2269.         rep movsd   ; insert index
  2270.         mov     eax, [ebp+NTFS.newRecord]
  2271.         stosd
  2272. ; split node
  2273.         mov     edi, [ebp+NTFS.cur_index_buf]
  2274.         mov     eax, edi
  2275.         add     eax, recordNode
  2276.         add     eax, [edi+recordNode+nodeRealSize]
  2277.         sub     eax, esi
  2278.         push    eax
  2279.         mov     ecx, [edi+recordNode+indexOffset]
  2280.         add     eax, ecx
  2281.         add     ecx, recordNode
  2282.         shr     ecx, 2
  2283.         push    esi
  2284.         mov     esi, edi
  2285.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2286.         rep movsd
  2287.         pop     esi
  2288.         pop     ecx
  2289.         shr     ecx, 2
  2290.         rep movsd
  2291.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2292.         mov     [edi+recordNode+nodeRealSize], eax
  2293.         pop     edi
  2294.         mov     cl, 4
  2295.         xor     eax, eax
  2296.         mov     esi, edi
  2297.         rep stosd
  2298.         mov     byte [esi+indexAllocatedSize], 16
  2299.         mov     byte [esi+indexFlags], 2
  2300.         mov     esi, [ebp+NTFS.cur_index_buf]
  2301.         mov     eax, [ebp+NTFS.newRecord]
  2302.         mov     [esi+recordVCN], eax
  2303.         add     esi, recordNode
  2304.         sub     edi, esi
  2305.         mov     [esi+nodeRealSize], edi
  2306.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2307.         mov     edx, [ebp+NTFS.LastRead]
  2308.         call    writeRecord
  2309.         jmp     .refresh
  2310.  
  2311. .common:
  2312.         add     edi, edx
  2313.         sub     edi, 4
  2314.         mov     esi, edi
  2315.         sub     esi, [esp]
  2316.         mov     ecx, esi
  2317.         sub     ecx, eax    ; eax = pointer in the record
  2318.         shr     ecx, 2
  2319.         inc     ecx
  2320.         std
  2321.         rep movsd           ; move forward, make space
  2322.         mov     ecx, [esp]
  2323.         shr     ecx, 2
  2324.         xor     eax, eax
  2325.         rep stosd
  2326.         cld
  2327.         add     edi, 4
  2328.         pop     ecx
  2329.         pop     esi
  2330.         mov     [edi+indexAllocatedSize], cx    ; fill index with data
  2331.         mov     eax, [esp]
  2332.         shl     eax, 1
  2333.         add     eax, 42h
  2334.         mov     [edi+indexRawSize], ax
  2335.         mov     eax, [ebp+NTFS.attr_iRecord]
  2336.         mov     [edi+directoryRecordReference], eax
  2337.         mov     eax, [ebp+NTFS.frs_buffer]
  2338.         mov     eax, [eax+reuseCounter]
  2339.         mov     [edi+directoryReferenceReuse], ax
  2340.         mov     eax, [ebp+NTFS.frs_size]
  2341.         shr     eax, 8
  2342.         add     ecx, 30h+48h+8+18h+8
  2343.         add     ecx, eax
  2344.         mov     eax, [ebp+NTFS.fileRealSize]
  2345.         add     ecx, eax
  2346.         mov     [edi+fileRealSize], eax
  2347.         cmp     [ebp+NTFS.frs_size], ecx
  2348.         jc      @f
  2349.         xor     eax, eax
  2350. @@:
  2351.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2352.         shl     ecx, 9
  2353.         add     eax, ecx
  2354.         dec     eax
  2355.         xor     edx, edx
  2356.         div     ecx
  2357.         mov     [ebp+NTFS.fileDataSize], eax
  2358.         mul     ecx
  2359.         mov     [edi+fileAllocatedSize], eax
  2360.         pop     ecx
  2361.         mov     [ebp+NTFS.indexPointer], edi
  2362.         mov     [edi+fileNameLength], cl
  2363.         add     edi, fileName
  2364. @@:         ; record filename
  2365.         lodsb
  2366.         call    ansi2uni_char
  2367.         stosw
  2368.         dec     ecx
  2369.         jnz     @b
  2370.         mov     eax, [ebp+NTFS.LastRead]
  2371.         mov     [ebp+NTFS.nodeLastRead], eax
  2372.         cmp     [ebp+NTFS.bFolder], 0
  2373.         jz      @f
  2374.         mov     edi, [ebp+NTFS.indexPointer]
  2375.         bts     dword [edi+fileFlags], 28
  2376.         jmp     .mftBitmap
  2377.  
  2378. @@: ; 3. File data
  2379.         cmp     [ebp+NTFS.fileDataSize], 0
  2380.         jz      .mftBitmap
  2381.         mov     edi, [ebp+NTFS.BitmapStart]
  2382.         call    ntfsSpaceAlloc
  2383.         jc      ntfsDiskFull
  2384.         mov     eax, [ebp+NTFS.fileDataStart]
  2385.         mul     [ebp+NTFS.sectors_per_cluster]
  2386.         mov     ecx, [ebp+NTFS.fileRealSize]
  2387.         add     ecx, 511
  2388.         shr     ecx, 9
  2389.         mov     ebx, [ebp+NTFS.fileDataBuffer]
  2390.         call    fs_write64_app
  2391.         test    eax, eax
  2392.         jnz     ntfsDevice
  2393.     ; 4. MFT record
  2394. .mftBitmap: ; search for free record
  2395.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2396.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2397.         mov     al, -1
  2398.         add     edi, 3
  2399.         sub     ecx, 3
  2400.         repz scasb
  2401.         dec     edi
  2402.         movzx   eax, byte [edi]
  2403.         not     al
  2404.         bsf     ecx, eax
  2405.         jz      .extendBitmapMFT    ; no free records
  2406.         bts     [edi], ecx
  2407. ; get record location
  2408.         sub     edi, [ebp+NTFS.mftBitmapBuffer]
  2409.         shl     edi, 3
  2410.         add     edi, ecx
  2411.         mov     [ebp+NTFS.newRecord], edi
  2412.         mov     eax, [ebp+NTFS.frs_size]
  2413.         shr     eax, 9
  2414.         mul     edi
  2415.         mov     [ebp+NTFS.cur_iRecord], 0
  2416.         mov     [ebp+NTFS.cur_attr], 0x80
  2417.         mov     [ebp+NTFS.cur_offs], eax
  2418.         push    eax
  2419.         mov     [ebp+NTFS.cur_size], 0
  2420.         mov     eax, [ebp+NTFS.frs_buffer]
  2421.         mov     [ebp+NTFS.cur_buf], eax
  2422.         call    ntfs_read_attr
  2423.         pop     eax
  2424.         jc      ntfsFail
  2425.         cmp     eax, [ebp+NTFS.mftSize]
  2426.         jnc     .extendMFT
  2427.         jmp     .mftRecord
  2428.  
  2429. .extendBitmapMFT:
  2430.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2431.         mov     [ebp+NTFS.cur_offs], eax
  2432.         shl     eax, 9
  2433.         cmp     [ebp+NTFS.mftBitmapSize], eax
  2434.         jnc     ntfsUnsupported
  2435.         mov     [ebp+NTFS.cur_iRecord], 0
  2436.         mov     [ebp+NTFS.cur_attr], 0xB0
  2437.         mov     [ebp+NTFS.cur_size], 0
  2438.         call    ntfs_read_attr
  2439.         jc      ntfsFail
  2440.         mov     eax, [ebp+NTFS.mft_cluster]
  2441.         mul     [ebp+NTFS.sectors_per_cluster]
  2442.         cmp     eax, [ebp+NTFS.LastRead]
  2443.         jnz     ntfsUnsupported     ; auxiliary record
  2444.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2445.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2446.         add     edi, ecx
  2447.         mov     eax, ecx
  2448.         mov     edx, [ebp+NTFS.attr_offs]
  2449.         add     ecx, 8
  2450.         mov     [edx+attributeRealSize], ecx
  2451.         mov     [edx+initialDataSize], ecx
  2452.         shl     eax, 3
  2453.         mov     [ebp+NTFS.newRecord], eax
  2454.         mov     dword [edi], 1
  2455.         mov     dword [edi+4], 0
  2456.         mov     [ebp+NTFS.cur_attr], 0x80
  2457.         mov     [ebp+NTFS.cur_offs], 0
  2458.         call    ntfs_read_attr.newAttribute
  2459.         jc      ntfsFail
  2460.         mov     [ebp+NTFS.mftBitmapSize], ecx
  2461. .extendMFT:
  2462.         mov     eax, [ebp+NTFS.mft_cluster]
  2463.         mul     [ebp+NTFS.sectors_per_cluster]
  2464.         cmp     eax, [ebp+NTFS.LastRead]
  2465.         jnz     ntfsUnsupported     ; auxiliary record
  2466.         mov     ecx, [ebp+NTFS.attr_offs]
  2467.         mov     eax, [ecx+attributeRealSize]
  2468.         mov     edx, [ecx+attributeRealSize+4]
  2469.         xor     ax, ax
  2470.         add     eax, 10000h
  2471.         adc     edx, 0
  2472.         push    [ebp+NTFS.fileDataStart]
  2473.         push    [ebp+NTFS.fileDataSize]
  2474.         call    resizeAttribute
  2475.         jc      ntfsErrorPop2
  2476.         mov     ebx, [ebp+NTFS.frs_buffer]
  2477.         mov     edx, [ebp+NTFS.LastRead]
  2478.         call    writeRecord     ; $MFT
  2479.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  2480.         mul     [ebp+NTFS.sectors_per_cluster]
  2481.         mov     ecx, [ebp+NTFS.frs_size]
  2482.         shr     ecx, 9
  2483.         call    fs_write64_sys  ; $MFTMirr
  2484. ; update $MFT retrieval information
  2485.         mov     edi, [ebp+NTFS.mft_retrieval_end]
  2486.         mov     eax, [edi-4]
  2487.         add     eax, [edi-8]
  2488.         mov     edx, [ebp+NTFS.fileDataSize]
  2489.         cmp     eax, [ebp+NTFS.fileDataStart]
  2490.         jnz     .newFragment
  2491.         add     [edi-8], edx
  2492.         jmp     @f
  2493. .newFragment:
  2494.         lea     eax, [ebp+NTFS.attrlist_buf]
  2495.         cmp     eax, edi
  2496.         jz      @f
  2497.         mov     [edi], edx
  2498.         mov     eax, [ebp+NTFS.fileDataStart]
  2499.         mov     [edi+4], eax
  2500.         add     [ebp+NTFS.mft_retrieval_end], 8
  2501. @@:
  2502.         mov     eax, [ebp+NTFS.fileDataSize]
  2503.         mul     [ebp+NTFS.sectors_per_cluster]
  2504.         add     [ebp+NTFS.mftSize], eax
  2505.         call    ntfsSpaceClean
  2506.         pop     [ebp+NTFS.fileDataSize]
  2507.         pop     [ebp+NTFS.fileDataStart]
  2508. .mftRecord:
  2509.         mov     ecx, [ebp+NTFS.frs_size]
  2510.         shr     ecx, 2
  2511.         mov     edi, [ebp+NTFS.frs_buffer]
  2512.         xor     eax, eax
  2513.         rep stosd
  2514.         mov     edi, [ebp+NTFS.frs_buffer]
  2515. ; record header
  2516.         rdtsc
  2517.         mov     [edi+2ah], ax
  2518.         mov     eax, [ebp+NTFS.frs_size]
  2519.         mov     [edi+recordAllocatedSize], eax
  2520.         shr     eax, 9
  2521.         inc     eax
  2522.         mov     [edi+updateSequenceSize], al
  2523.         shl     eax, 1
  2524.         add     eax, 2ah+7
  2525.         and     eax, not 7
  2526.         mov     dword[edi], 'FILE'
  2527.         mov     byte [edi+updateSequenceOffset], 2ah
  2528.         mov     byte [edi+hardLinkCounter], 1
  2529.         mov     byte [edi+newAttributeID], 3
  2530.         mov     [edi+attributeOffset], al
  2531.         add     edi, eax
  2532. ; $StandardInformation
  2533.         mov     byte [edi+attributeType], 10h
  2534.         mov     byte [edi+sizeWithHeader], 48h
  2535.         mov     byte [edi+sizeWithoutHeader], 30h
  2536.         mov     byte [edi+attributeOffset], 18h
  2537.         add     edi, 48h
  2538. ; $FileName
  2539.         mov     esi, [ebp+NTFS.indexPointer]
  2540.         mov     byte [edi+attributeType], 30h
  2541.         mov     byte [edi+attributeID], 1
  2542.         mov     byte [edi+attributeOffset], 18h
  2543.         mov     byte [edi+indexedFlag], 1
  2544.         mov     cx, [esi+indexRawSize]
  2545.         mov     [edi+sizeWithoutHeader], ecx
  2546.         mov     cx, [esi+indexAllocatedSize]
  2547.         add     ecx, 8
  2548.         mov     [edi+sizeWithHeader], ecx
  2549.         add     edi, 18h
  2550.         add     esi, 16
  2551.         sub     ecx, 18h
  2552.         shr     ecx, 2
  2553.         rep movsd
  2554.         mov     byte [edi+sizeWithHeader], 50h
  2555.         mov     byte [edi+attributeID], 2
  2556.         cmp     [ebp+NTFS.bFolder], 1
  2557.         jz      .indexRoot
  2558. ; $Data
  2559.         mov     byte [edi+attributeType], 80h
  2560.         mov     eax, [ebp+NTFS.fileDataSize]
  2561.         test    eax, eax
  2562.         jz      .resident
  2563.         mov     esi, [ebp+NTFS.indexPointer]
  2564.         dec     eax
  2565.         mov     [edi+lastVCN], eax
  2566.         mov     byte [edi+nonResidentFlag], 1
  2567.         mov     byte [edi+dataRunsOffset], 40h
  2568.         mov     eax, [esi+fileAllocatedSize]
  2569.         mov     [edi+attributeAllocatedSize], eax
  2570.         mov     eax, [esi+fileRealSize]
  2571.         mov     [edi+attributeRealSize], eax
  2572.         mov     [edi+initialDataSize], eax
  2573.         push    edi
  2574.         mov     esi, edi
  2575.         add     edi, 40h
  2576.         call    createMcbEntry
  2577.         inc     edi
  2578.         jmp     @f
  2579.  
  2580. .resident:
  2581.         mov     ecx, [ebp+NTFS.fileRealSize]
  2582.         mov     [edi+sizeWithoutHeader], ecx
  2583.         mov     byte [edi+attributeOffset], 18h
  2584.         push    edi
  2585.         mov     esi, [ebp+NTFS.fileDataBuffer]
  2586.         add     edi, 18h
  2587.         rep movsb
  2588. @@:
  2589.         mov     eax, edi
  2590.         pop     edi
  2591.         sub     eax, edi
  2592.         add     eax, 7
  2593.         and     eax, not 7
  2594.         mov     [edi+sizeWithHeader], eax
  2595.         add     edi, eax
  2596.         mov     al, 1
  2597.         jmp     .end
  2598.  
  2599. .indexRoot:
  2600.         mov     byte [edi+attributeType], 90h
  2601.         mov     byte [edi+nameLength], 4
  2602.         mov     byte [edi+nameOffset], 18h
  2603.         mov     byte [edi+sizeWithoutHeader], 30h
  2604.         mov     byte [edi+attributeOffset], 20h
  2605.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2606.         mov     dword[edi+18h+4], 300033h
  2607.         mov     byte [edi+20h+indexedAttributesType], 30h
  2608.         mov     byte [edi+20h+collationRule], 1
  2609.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2610.         mov     dl, 1
  2611.         shl     eax, 8
  2612. @@:
  2613.         shl     eax, 1
  2614.         shl     edx, 1
  2615.         cmp     eax, [ebp+NTFS.frs_size]
  2616.         jc      @b
  2617.         shr     edx, 1
  2618.         mov     [edi+20h+indexRecordSize], eax
  2619.         mov     [edi+20h+indexRecordSizeClus], dl
  2620.         mov     byte [edi+30h+indexOffset], 16
  2621.         mov     byte [edi+30h+nodeRealSize], 32
  2622.         mov     byte [edi+30h+nodeAllocatedSize], 32
  2623.         mov     byte [edi+40h+indexAllocatedSize], 16
  2624.         mov     byte [edi+40h+indexFlags], 2
  2625.         add     edi, 50h
  2626.         mov     al, 3
  2627. .end:
  2628.         mov     ebx, [ebp+NTFS.frs_buffer]
  2629.         mov     dword [edi], -1
  2630.         mov     dword [edi+4], 0
  2631.         add     edi, 8
  2632.         sub     edi, ebx
  2633.         mov     [ebx+recordFlags], al
  2634.         mov     [ebx+recordRealSize], edi
  2635.         mov     edx, [ebp+NTFS.LastRead]
  2636.         call    writeRecord
  2637. ; write MFT bitmap
  2638.         mov     eax, [ebp+NTFS.newRecord]
  2639.         shr     eax, 3+9
  2640.         mov     ebx, eax
  2641.         shl     ebx, 9
  2642.         add     eax, [ebp+NTFS.mftBitmapLocation]
  2643.         add     ebx, [ebp+NTFS.mftBitmapBuffer]
  2644.         mov     ecx, 1
  2645.         xor     edx, edx
  2646.         call    fs_write64_sys
  2647.         mov     edi, [ebp+NTFS.indexPointer]
  2648.         mov     eax, [ebp+NTFS.newRecord]
  2649.         mov     [edi+fileRecordReference], eax
  2650. ; 5. Write directory node
  2651.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2652.         mov     edx, [ebp+NTFS.nodeLastRead]
  2653.         call    writeRecord
  2654.         mov     ebx, [ebp+NTFS.fileRealSize]
  2655. ntfsDone:
  2656.         mov     esi, [ebp+PARTITION.Disk]
  2657.         call    disk_sync
  2658.         call    ntfs_unlock
  2659.         xor     eax, eax
  2660.         ret
  2661.  
  2662. writeRecord:
  2663. ; make updateSequence and write to disk
  2664. ;   in:
  2665. ; ebx -> record
  2666. ; edx = partition sector
  2667.         mov     esi, ebx
  2668.         mov     edi, ebx
  2669.         movzx   ecx, word [esi+updateSequenceOffset]
  2670.         add     edi, ecx
  2671.         mov     ax, [edi]
  2672.         inc     ax
  2673.         stosw
  2674.         mov     cx, [esi+updateSequenceSize]
  2675.         dec     ecx
  2676.         push    ecx
  2677. @@:
  2678.         add     esi, 510
  2679.         movsw
  2680.         mov     [esi-2], ax
  2681.         dec     ecx
  2682.         jnz     @b
  2683.         mov     eax, edx
  2684.         xor     edx, edx
  2685.         pop     ecx
  2686.         jmp     fs_write64_sys
  2687.  
  2688. createMcbEntry:
  2689. ;   in:
  2690. ; [ebp+NTFS.fileDataStart] = position value
  2691. ; [ebp+NTFS.fileDataSize] = size value
  2692. ; edi -> destination
  2693. ; esi -> attribute header
  2694.         mov     eax, [ebp+NTFS.fileDataStart]
  2695.         xor     edx, edx
  2696.         shl     eax, 1
  2697.         jnc     @f
  2698.         not     eax
  2699. @@:
  2700.         inc     edx
  2701.         shr     eax, 8
  2702.         jnz     @b
  2703.         mov     eax, [ebp+NTFS.fileDataSize]
  2704.         shl     eax, 1
  2705.         xor     ecx, ecx
  2706. @@:
  2707.         inc     ecx
  2708.         shr     eax, 8
  2709.         jnz     @b
  2710.         lea     eax, [edi+edx+1]
  2711.         add     eax, ecx
  2712.         sub     eax, esi
  2713.         sub     eax, [esi+sizeWithHeader]
  2714.         jc      @f
  2715.         add     word [esi+sizeWithHeader], 8    ; extend attribute
  2716.         mov     esi, [ebp+NTFS.frs_buffer]
  2717.         mov     eax, [esi+recordRealSize]
  2718.         add     eax, 8
  2719.         cmp     [esi+recordAllocatedSize], eax
  2720.         jc      .end    ; no space in the record
  2721.         mov     [esi+recordRealSize], eax
  2722.         push    ecx edi
  2723.         add     esi, eax
  2724.         mov     ecx, esi
  2725.         sub     ecx, edi
  2726.         sub     ecx, 8
  2727.         shr     ecx, 2
  2728.         mov     edi, esi
  2729.         sub     edi, 4
  2730.         sub     esi, 12
  2731.         std
  2732.         rep movsd
  2733.         cld
  2734.         pop     edi ecx
  2735. @@:
  2736.         mov     eax, edx
  2737.         shl     eax, 4
  2738.         add     eax, ecx
  2739.         stosb
  2740.         lea     esi, [ebp+NTFS.fileDataSize]
  2741.         rep movsb
  2742.         lea     esi, [ebp+NTFS.fileDataStart]
  2743.         mov     ecx, edx
  2744.         rep movsb
  2745.         mov     [edi], cl
  2746. .end:
  2747.         ret
  2748.  
  2749. resizeAttribute:
  2750. ;   in:
  2751. ; [ebp+NTFS.frs_buffer] -> file record
  2752. ; [ebp+NTFS.attr_offs] -> attribute
  2753. ; edx:eax = new size
  2754. ;   out:
  2755. ; [ebp+NTFS.fileDataSize] = clusters added (positive)
  2756. ; [ebp+NTFS.fileDataStart] = added block
  2757. ; CF=1 -> eax = error code
  2758.         mov     esi, [ebp+NTFS.attr_offs]
  2759.         mov     dword [ebp+NTFS.attr_size], eax
  2760.         mov     dword [ebp+NTFS.attr_size+4], edx
  2761.         cmp     byte [esi+nonResidentFlag], 0
  2762.         jz      .resident
  2763.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2764.         shl     ecx, 9
  2765.         mov     [esi+attributeRealSize], eax
  2766.         mov     [esi+attributeRealSize+4], edx
  2767.         mov     [esi+initialDataSize], eax
  2768.         mov     [esi+initialDataSize+4], edx
  2769.         sub     eax, 1
  2770.         sbb     edx, 0
  2771.         jc      .makeResident
  2772.         div     ecx
  2773.         mov     edi, eax
  2774.         inc     eax
  2775.         mul     ecx
  2776.         mov     [esi+attributeAllocatedSize], eax
  2777.         mov     [esi+attributeAllocatedSize+4], edx
  2778.         mov     ecx, [esi+lastVCN]
  2779.         mov     [esi+lastVCN], edi
  2780.         movzx   eax, byte [esi+dataRunsOffset]
  2781.         sub     edi, ecx
  2782.         mov     [ebp+NTFS.fileDataSize], edi
  2783.         jz      .done
  2784.         jc      .shrinkAttribute
  2785. ; extend attribute
  2786.         xor     edi, edi
  2787.         add     esi, eax
  2788.         push    edi edi edi edi
  2789. @@:
  2790.         mov     edx, eax
  2791.         mov     eax, esi
  2792.         add     edi, [esp+8]
  2793.         call    ntfs_decode_mcb_entry
  2794.         jc      @b
  2795.         mov     [esp+4], edx
  2796.         mov     [esp+12], edi
  2797.         add     edi, [esp]
  2798.         push    edi
  2799.         shr     edi, 5
  2800.         shl     edi, 2
  2801.         push    eax
  2802.         cmp     [ebp+NTFS.cur_iRecord], 0
  2803.         jz      @f
  2804.         cmp     edi, [ebp+NTFS.BitmapStart]
  2805.         jc      .err1
  2806. @@:
  2807.         call    ntfsSpaceAlloc
  2808.         jc      .err1
  2809.         mov     eax, [ebp+NTFS.fileDataStart]
  2810.         pop     edi
  2811.         pop     edx
  2812.         cmp     edx, eax
  2813.         jnz     .newEntry
  2814.         pop     edx
  2815.         pop     edi
  2816.         pop     [ebp+NTFS.fileDataStart]
  2817.         mov     [esp], eax
  2818.         push    [ebp+NTFS.fileDataSize]
  2819.         add     [ebp+NTFS.fileDataSize], edx
  2820.         jmp     @f
  2821.  
  2822. .newEntry:
  2823.         add     esp, 12
  2824.         pop     edx
  2825.         push    eax
  2826.         push    [ebp+NTFS.fileDataSize]
  2827.         sub     eax, edx
  2828.         mov     [ebp+NTFS.fileDataStart], eax
  2829. @@:
  2830.         mov     esi, [ebp+NTFS.attr_offs]
  2831.         call    createMcbEntry
  2832.         pop     [ebp+NTFS.fileDataSize]
  2833.         pop     [ebp+NTFS.fileDataStart]
  2834.         movi    eax, ERROR_UNSUPPORTED_FS
  2835. .done:
  2836.         ret
  2837.  
  2838. .err1:
  2839.         add     esp, 24
  2840.         stc
  2841. .err2:
  2842.         movi    eax, ERROR_DISK_FULL
  2843.         ret
  2844.  
  2845. .err3:
  2846.         movi    eax, ERROR_FS_FAIL
  2847.         add     esp, 20
  2848.         stc
  2849.         ret
  2850.  
  2851. .shrinkAttribute:
  2852.         add     ecx, edi
  2853.         inc     ecx
  2854.         add     esi, eax
  2855.         xor     edi, edi
  2856.         sub     esp, 20
  2857. @@:
  2858.         mov     [esp+16], esi
  2859.         call    ntfs_decode_mcb_entry
  2860.         jnc     .err3
  2861.         add     edi, [esp+8]
  2862.         sub     ecx, [esp]
  2863.         jnc     @b
  2864.         mov     ebx, ecx
  2865.         add     ecx, [esp]
  2866.         mov     eax, [esp+8]
  2867.         mov     [ebp+NTFS.fileDataSize], ecx
  2868.         mov     [ebp+NTFS.fileDataStart], eax
  2869.         push    edi
  2870.         add     edi, ecx
  2871.         neg     ebx
  2872.         call    ntfsSpaceFree
  2873.         pop     edi
  2874.         jc      .end
  2875. @@:
  2876.         call    ntfs_decode_mcb_entry
  2877.         jnc     .end
  2878.         cmp     dword[esp+8], 0
  2879.         jz      @b
  2880.         add     edi, [esp+8]
  2881.         mov     ebx, [esp]
  2882.         call    ntfsSpaceFree
  2883.         jnc     @b
  2884. .end:
  2885.         add     esp, 16
  2886.         pop     edi
  2887.         cmp     [ebp+NTFS.fileDataSize], 0
  2888.         jz      @f
  2889.         mov     esi, [ebp+NTFS.attr_offs]
  2890.         call    createMcbEntry
  2891.         mov     [ebp+NTFS.fileDataSize], 0
  2892. @@:
  2893.         ret
  2894.  
  2895. .resident:
  2896.         test    edx, edx
  2897.         jnz     .nonResident
  2898.         cmp     eax, 8000h
  2899.         jnc     .nonResident
  2900.         add     ax, [esi+attributeOffset]
  2901.         sub     eax, [esi+sizeWithHeader]
  2902.         jc      @f
  2903.         mov     edi, [ebp+NTFS.frs_buffer]
  2904.         mov     ecx, eax
  2905.         add     ecx, [edi+recordRealSize]
  2906.         cmp     [edi+recordAllocatedSize], ecx
  2907.         jc      .nonResident
  2908.         add     eax, 7
  2909.         and     eax, not 7
  2910.         add     [edi+recordRealSize], eax
  2911.         add     edi, [edi+recordRealSize]
  2912.         add     [esi+sizeWithHeader], eax
  2913.         add     esi, [esi+sizeWithHeader]
  2914.         mov     ecx, edi
  2915.         sub     ecx, esi
  2916.         shr     ecx, 2
  2917.         sub     edi, 4
  2918.         mov     esi, edi
  2919.         sub     esi, eax
  2920.         std
  2921.         rep movsd
  2922.         mov     ecx, eax
  2923.         shr     ecx, 2
  2924.         xor     eax, eax
  2925.         rep stosd
  2926.         cld
  2927.         mov     esi, [ebp+NTFS.attr_offs]
  2928. @@:
  2929.         mov     eax, dword [ebp+NTFS.attr_size]
  2930.         mov     [esi+sizeWithoutHeader], eax
  2931.         mov     [ebp+NTFS.fileDataSize], 0
  2932.         clc
  2933.         ret
  2934.  
  2935. .nonResident:   ; convert resident to non-resident
  2936.         mov     eax, dword [ebp+NTFS.attr_size]
  2937.         sub     eax, 1
  2938.         sbb     edx, 0
  2939.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2940.         shl     ecx, 9
  2941.         div     ecx
  2942.         inc     eax
  2943.         mov     [ebp+NTFS.fileDataSize], eax
  2944.         mov     edi, [ebp+NTFS.BitmapStart]
  2945.         push    ecx
  2946.         call    ntfsSpaceAlloc
  2947.         pop     ecx
  2948.         jc      .err2
  2949.         mov     esi, [ebp+NTFS.attr_offs]
  2950.         xor     eax, eax
  2951.         xor     edx, edx
  2952. @@:
  2953.         add     eax, ecx
  2954.         inc     edx
  2955.         cmp     eax, [esi+sizeWithoutHeader]
  2956.         jc      @b
  2957.         push    edx
  2958.         push    eax
  2959.         stdcall kernel_alloc, eax
  2960.         mov     ecx, [esp]
  2961.         shr     ecx, 2
  2962.         mov     edi, eax
  2963.         mov     ebx, eax
  2964.         xor     eax, eax
  2965.         rep stosd
  2966.         mov     al, [esi+attributeOffset]
  2967.         mov     ecx, [esi+sizeWithoutHeader]
  2968.         add     esi, eax
  2969.         mov     edi, ebx
  2970.         rep movsb
  2971.         mov     eax, [ebp+NTFS.fileDataStart]
  2972.         mul     [ebp+NTFS.sectors_per_cluster]
  2973.         pop     ecx
  2974.         shr     ecx, 9
  2975.         call    fs_write64_app
  2976.         stdcall kernel_free, ebx
  2977.         mov     esi, [ebp+NTFS.attr_offs]
  2978.         add     esi, [esi+sizeWithHeader]
  2979.         mov     ecx, [ebp+NTFS.frs_buffer]
  2980.         add     ecx, [ecx+recordRealSize]
  2981.         sub     ecx, esi
  2982.         shr     ecx, 2
  2983.         lea     edi, [ebp+NTFS.bitmap_buf]
  2984.         push    ecx
  2985.         rep movsd
  2986.         mov     edi, [ebp+NTFS.attr_offs]
  2987.         add     edi, 16
  2988.         mov     cl, 6
  2989.         xor     eax, eax
  2990.         rep stosd
  2991.         mov     edi, [ebp+NTFS.attr_offs]
  2992.         mov     eax, [ebp+NTFS.fileDataSize]
  2993.         dec     eax
  2994.         mov     [edi+lastVCN], eax
  2995.         inc     eax
  2996.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2997.         shl     ecx, 9
  2998.         mul     ecx
  2999.         mov     byte [edi+sizeWithHeader], 50h
  3000.         mov     byte [edi+nonResidentFlag], 1
  3001.         mov     byte [edi+dataRunsOffset], 40h
  3002.         mov     [edi+attributeAllocatedSize], eax
  3003.         mov     [edi+attributeAllocatedSize+4], edx
  3004.         mov     eax, dword [ebp+NTFS.attr_size]
  3005.         mov     edx, dword [ebp+NTFS.attr_size+4]
  3006.         mov     [edi+attributeRealSize], eax
  3007.         mov     [edi+attributeRealSize+4], edx
  3008.         mov     [edi+initialDataSize], eax
  3009.         mov     [edi+initialDataSize+4], edx
  3010.         mov     esi, edi
  3011.         add     edi, 40h
  3012.         call    createMcbEntry
  3013.         mov     eax, edi
  3014.         mov     edi, [ebp+NTFS.attr_offs]
  3015.         sub     eax, edi
  3016.         add     eax, 8
  3017.         and     eax, not 7
  3018.         mov     [edi+sizeWithHeader], eax
  3019.         pop     ecx
  3020.         lea     esi, [ebp+NTFS.bitmap_buf]
  3021.         add     edi, eax
  3022.         rep movsd
  3023.         mov     esi, [ebp+NTFS.frs_buffer]
  3024.         sub     edi, esi
  3025.         mov     [esi+recordRealSize], edi
  3026.         pop     edx
  3027.         sub     [ebp+NTFS.fileDataSize], edx
  3028.         add     [ebp+NTFS.fileDataStart], edx
  3029.         ret
  3030.  
  3031. .makeResident:  ; convert non-resident to empty resident
  3032.         movzx   eax, byte [esi+dataRunsOffset]
  3033.         mov     byte [esi+nonResidentFlag], 0
  3034.         mov     dword [esi+sizeWithoutHeader], 0
  3035.         mov     dword [esi+attributeOffset], 18h
  3036.         add     esi, eax
  3037.         xor     edi, edi
  3038.         sub     esp, 16
  3039. @@:
  3040.         call    ntfs_decode_mcb_entry
  3041.         jnc     @f
  3042.         cmp     dword[esp+8], 0
  3043.         jz      @b
  3044.         add     edi, [esp+8]
  3045.         mov     ebx, [esp]
  3046.         call    ntfsSpaceFree
  3047.         jnc     @b
  3048. @@:
  3049.         add     esp, 16
  3050.         mov     [ebp+NTFS.fileDataSize], 0
  3051.         ret
  3052.  
  3053. ntfsSpaceClean:
  3054. ; clean up to 16 Mb of disk space
  3055. ;   in:
  3056. ; [ebp+NTFS.fileDataStart] = block to clean
  3057. ; [ebp+NTFS.fileDataSize] = block size
  3058.         mov     eax, [ebp+NTFS.fileDataSize]
  3059.         test    eax, eax
  3060.         jz      @f
  3061.         mul     [ebp+NTFS.sectors_per_cluster]
  3062.         cmp     eax, 8001h
  3063.         jnc     @f
  3064.         push    eax
  3065.         shl     eax, 9
  3066.         stdcall kernel_alloc, eax
  3067.         pop     ecx
  3068.         test    eax, eax
  3069.         jz      @f
  3070.         push    ecx
  3071.         shl     ecx, 7
  3072.         mov     edi, eax
  3073.         mov     ebx, eax
  3074.         xor     eax, eax
  3075.         rep stosd
  3076.         mov     eax, [ebp+NTFS.fileDataStart]
  3077.         mul     [ebp+NTFS.sectors_per_cluster]
  3078.         mov     [ebp+NTFS.LastRead], eax
  3079.         pop     ecx
  3080.         call    fs_write64_app
  3081.         stdcall kernel_free, ebx
  3082. @@:
  3083.         ret
  3084.  
  3085. ntfsSpaceAlloc:
  3086. ; allocate disk space
  3087. ;   in:
  3088. ; edi = offset in bitmap to start search from
  3089. ; [ebp+NTFS.fileDataSize] = block size in clusters
  3090. ;   out:
  3091. ; [ebp+NTFS.fileDataStart] = allocated block starting cluster
  3092. ; CF=1 -> disk full
  3093.         push    eax
  3094.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3095.         add     edi, ecx
  3096.         add     ecx, [ebp+NTFS.BitmapSize]
  3097.         sub     ecx, edi
  3098.         jnc     @f
  3099.         call    bitmapBuffering
  3100.         shl     ecx, 2
  3101. @@:
  3102.         shr     ecx, 2
  3103.         mov     eax, [ebp+NTFS.fileDataSize]
  3104.         shr     eax, 5
  3105.         jz      .small
  3106.         mov     ebx, eax    ; bitmap dwords
  3107. .start:
  3108.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3109.         add     ecx, [ebp+NTFS.BitmapSize]
  3110.         sub     ecx, edi
  3111.         shr     ecx, 2
  3112. @@:
  3113.         xor     eax, eax
  3114.         repnz scasd         ; search for empty dword
  3115.         jz      @f
  3116.         call    bitmapBuffering
  3117.         jmp     @b
  3118. @@:
  3119.         cmp     ecx, ebx
  3120.         jnc     @f
  3121.         call    bitmapBuffering
  3122.         jmp     @b
  3123. @@:
  3124.         sub     edi, 4
  3125.         mov     ecx, ebx
  3126.         mov     esi, edi
  3127.         xor     eax, eax
  3128.         repz scasd          ; check following dwords
  3129.         jnz     .start
  3130.         sub     esi, 4
  3131.         mov     eax, [esi]
  3132.         xor     edx, edx
  3133.         bsr     edx, eax
  3134.         inc     edx
  3135.         push    edx         ; starting bit
  3136.         push    esi         ; starting dword
  3137.         add     esi, 4
  3138.         neg     edx
  3139.         add     edx, 32
  3140.         mov     eax, [ebp+NTFS.fileDataSize]
  3141.         sub     eax, edx
  3142.         mov     edx, eax
  3143.         shr     eax, 5
  3144.         shl     eax, 2
  3145.         add     esi, eax
  3146.         mov     eax, [esi]
  3147.         bsf     ecx, eax    ; check last dword
  3148.         jz      .done
  3149.         and     edx, 31
  3150.         cmp     ecx, edx
  3151.         jnc     .done
  3152.         add     esp, 8
  3153.         jmp     .start
  3154.  
  3155. .small:     ; less than 32 clusters
  3156.         mov     eax, -1
  3157.         repz scasd          ; search for zero bits
  3158.         test    ecx, ecx
  3159.         jnz     @f
  3160.         call    bitmapBuffering
  3161.         jmp     .small
  3162. @@:
  3163.         sub     edi, 4
  3164.         mov     eax, [edi]
  3165.         not     eax
  3166. @@:
  3167.         bsf     ebx, eax    ; first 0
  3168.         jz      .again
  3169.         not     eax
  3170.         shr     eax, cl
  3171.         shl     eax, cl
  3172.         bsf     edx, eax    ; next 1
  3173.         jz      @f
  3174.         sub     edx, ebx
  3175.         cmp     edx, [ebp+NTFS.fileDataSize]
  3176.         jnc     .got        ; fits inside
  3177.         bsf     ebx, eax
  3178.         not     eax
  3179.         shr     eax, cl
  3180.         shl     eax, cl
  3181.         jmp     @b
  3182. @@:         ; next dword
  3183.         mov     eax, [edi+4]
  3184.         bsf     edx, eax
  3185.         jz      .got        ; empty
  3186.         add     edx, 32
  3187.         sub     edx, ebx
  3188.         cmp     edx, [ebp+NTFS.fileDataSize]
  3189.         jnc     .got        ; share between dwords
  3190. .again:
  3191.         add     edi, 4
  3192.         jmp     .small
  3193.  
  3194. .got:
  3195.         push    ebx         ; starting bit
  3196.         push    edi         ; starting dword
  3197. .done:      ; mark space
  3198.         mov     ecx, [esp+4]
  3199.         cmp     ecx, 32
  3200.         jc      @f
  3201.         xor     ecx, ecx
  3202.         add     dword [esp], 4
  3203.         mov     [esp+4], ecx
  3204. @@:
  3205.         mov     edi, [esp]
  3206.         xor     eax, eax
  3207.         dec     eax
  3208.         shr     eax, cl
  3209.         shl     eax, cl
  3210.         neg     ecx
  3211.         add     ecx, 32
  3212.         sub     ecx, [ebp+NTFS.fileDataSize]
  3213.         jc      @f
  3214.         shl     eax, cl     ; fits inside dword
  3215.         shr     eax, cl
  3216.         or      [edi], eax
  3217.         jmp     .end
  3218.  
  3219. @@:
  3220.         or      [edi], eax
  3221.         neg     ecx
  3222.         push    ecx
  3223.         shr     ecx, 5
  3224.         add     edi, 4
  3225.         xor     eax, eax
  3226.         dec     eax
  3227.         rep stosd
  3228.         pop     ecx
  3229.         and     ecx, 31
  3230.         shr     eax, cl
  3231.         shl     eax, cl
  3232.         not     eax
  3233.         or      [edi], eax
  3234. .end:
  3235.         pop     eax
  3236.         pop     ecx
  3237.         sub     eax, [ebp+NTFS.BitmapBuffer]
  3238.         shl     eax, 3
  3239.         add     eax, ecx
  3240.         pop     ecx
  3241.         mov     ecx, [ebp+NTFS.fileDataSize]
  3242.         mov     [ebp+NTFS.fileDataStart], eax
  3243.         add     ecx, eax
  3244.         add     ecx, 4095
  3245.         shr     ecx, 3+9
  3246.         shr     eax, 3+9
  3247.         sub     ecx, eax
  3248.         mov     ebx, eax
  3249.         shl     ebx, 9
  3250.         add     eax, [ebp+NTFS.BitmapLocation]
  3251.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3252.         xor     edx, edx
  3253.         jmp     fs_write64_app
  3254.  
  3255. ntfsSpaceFree:
  3256. ; free disk space
  3257. ;   in:
  3258. ; edi = starting cluster
  3259. ; ebx = size in clusters
  3260.         mov     eax, edi
  3261.         add     eax, ebx
  3262.         shr     eax, 3
  3263.         inc     eax
  3264.         cmp     eax, [ebp+NTFS.BitmapSize]
  3265.         jc      @f
  3266.         add     eax, [ebp+NTFS.BitmapBuffer]
  3267.         push    edi
  3268.         mov     edi, eax
  3269.         call    bitmapBuffering
  3270.         pop     edi
  3271. @@:
  3272.         push    edi
  3273.         mov     ecx, edi
  3274.         shr     edi, 5
  3275.         shl     edi, 2
  3276.         add     edi, [ebp+NTFS.BitmapBuffer]
  3277.         and     ecx, 31
  3278.         xor     eax, eax
  3279.         dec     eax
  3280.         shr     eax, cl
  3281.         shl     eax, cl
  3282.         neg     ecx
  3283.         add     ecx, 32
  3284.         sub     ecx, ebx
  3285.         jc      @f
  3286.         shl     eax, cl     ; fits inside dword
  3287.         shr     eax, cl
  3288.         not     eax
  3289.         and     [edi], eax
  3290.         jmp     .writeBitmap
  3291.  
  3292. @@:
  3293.         not     eax
  3294.         and     [edi], eax
  3295.         neg     ecx
  3296.         push    ecx
  3297.         shr     ecx, 5
  3298.         add     edi, 4
  3299.         xor     eax, eax
  3300.         rep stosd
  3301.         pop     ecx
  3302.         and     ecx, 31
  3303.         dec     eax
  3304.         shr     eax, cl
  3305.         shl     eax, cl
  3306.         and     [edi], eax
  3307. .writeBitmap:
  3308.         pop     eax
  3309.         mov     edi, eax
  3310.         lea     ecx, [eax+ebx+4095]
  3311.         shr     eax, 3+9
  3312.         shr     ecx, 3+9
  3313.         sub     ecx, eax
  3314.         mov     ebx, eax
  3315.         shl     ebx, 9
  3316.         add     eax, [ebp+NTFS.BitmapLocation]
  3317.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3318.         xor     edx, edx
  3319.         jmp     fs_write64_app
  3320.  
  3321. bitmapBuffering:
  3322. ; Extend BitmapBuffer and read next 32kb of bitmap
  3323. ; Warning: $Bitmap fragmentation is not foreseen
  3324. ; in: edi -> position in bitmap buffer
  3325. ; out: ecx = number of buffered dwords left
  3326.         push    ebx
  3327.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3328.         cmp     eax, [ebp+NTFS.BitmapSize]
  3329.         jz      .end
  3330.         stdcall alloc_pages, 8
  3331.         test    eax, eax
  3332.         jz      .end
  3333.         add     eax, 3
  3334.         mov     ebx, [ebp+NTFS.BitmapBuffer]
  3335.         add     ebx, [ebp+NTFS.BitmapSize]
  3336.         push    ebx
  3337.         mov     ecx, 8
  3338.         call    commit_pages
  3339.         mov     eax, [ebp+NTFS.BitmapSize]
  3340.         shr     eax, 9
  3341.         add     eax, [ebp+NTFS.BitmapLocation]
  3342.         pop     ebx
  3343.         mov     ecx, 64
  3344.         xor     edx, edx
  3345.         call    fs_read64_app
  3346.         test    eax, eax
  3347.         jnz     .err
  3348.         add     [ebp+NTFS.BitmapSize], 8000h
  3349.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3350.         cmp     eax, [ebp+NTFS.BitmapSize]
  3351.         jnc     @f
  3352.         mov     [ebp+NTFS.BitmapSize], eax
  3353. @@:
  3354.         pop     ebx
  3355.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3356.         add     ecx, [ebp+NTFS.BitmapSize]
  3357.         sub     ecx, edi
  3358.         jc      bitmapBuffering
  3359.         shr     ecx, 2
  3360.         ret
  3361.  
  3362. .err:
  3363.         mov     eax, [ebp+NTFS.BitmapBuffer]
  3364.         add     eax, [ebp+NTFS.BitmapSize]
  3365.         mov     ecx, 8
  3366.         call    release_pages
  3367. .end:
  3368.         add     esp, 12     ; ret
  3369.         stc
  3370.         ret
  3371.  
  3372. ;----------------------------------------------------------------
  3373. ntfs_WriteFile:
  3374.         cmp     byte [esi], 0
  3375.         jnz     @f
  3376.         xor     ebx, ebx
  3377.         movi    eax, ERROR_ACCESS_DENIED
  3378.         ret
  3379. @@:
  3380.         call    ntfs_lock
  3381.         stdcall ntfs_find_lfn, [esp+4]
  3382.         jc      ntfsNotFound
  3383.         cmp     [ebp+NTFS.cur_iRecord], 16
  3384.         jc      ntfsDenied
  3385.         bt      dword [eax+fileFlags], 28
  3386.         jc      ntfsDenied
  3387.         cmp     [ebp+NTFS.fragmentCount], 1
  3388.         jnz     ntfsUnsupported     ; record fragmented
  3389. ; edit directory node
  3390.         mov     edi, [ebp+NTFS.cur_index_buf]
  3391.         cmp     dword [edi], 'INDX'
  3392.         jz      @f
  3393.         mov     esi, [ebp+NTFS.frs_buffer]
  3394.         mov     ecx, [esi+recordRealSize]
  3395.         shr     ecx, 2
  3396.         rep movsd
  3397.         mov     esi, [ebp+NTFS.attr_offs]
  3398.         mov     cl, [esi+attributeOffset]
  3399.         sub     esi, [ebp+NTFS.frs_buffer]
  3400.         add     eax, ecx
  3401.         add     eax, esi
  3402. @@:
  3403.         mov     ecx, [ebx+4]
  3404.         mov     edx, [ebx+8]
  3405.         add     ecx, [ebx+12]
  3406.         adc     edx, 0
  3407.         mov     [eax+fileRealSize], ecx
  3408.         mov     [eax+fileRealSize+4], edx
  3409.         mov     eax, [ebp+NTFS.LastRead]
  3410.         mov     [ebp+NTFS.nodeLastRead], eax
  3411.         mov     [ebp+NTFS.cur_attr], 0x80
  3412.         mov     [ebp+NTFS.cur_offs], 0
  3413.         mov     [ebp+NTFS.cur_size], 0
  3414.         call    ntfs_read_attr
  3415.         jc      ntfsFail
  3416.         mov     eax, ecx
  3417.         mov     ecx, [ebp+NTFS.frs_buffer]
  3418.         cmp     word [ecx+baseRecordReuse], 0
  3419.         jnz     ntfsUnsupported     ; auxiliary record
  3420.         mov     ecx, [ebp+NTFS.attr_offs]
  3421.         cmp     word [ecx+attributeFlags], 0
  3422.         jnz     ntfsUnsupported
  3423.         push    ebx
  3424.         cmp     byte [ecx+nonResidentFlag], 0
  3425.         jz      .resizeAttribute
  3426.         cmp     edx, [ecx+attributeRealSize+4]
  3427.         jc      .writeNode
  3428.         jnz     .resizeAttribute
  3429.         cmp     [ecx+attributeRealSize], eax
  3430.         jnc     .writeNode
  3431. .resizeAttribute:
  3432.         call    resizeAttribute
  3433.         jc      ntfsErrorPop
  3434.         mov     ecx, [ebp+NTFS.attr_offs]
  3435.         cmp     byte [ecx+nonResidentFlag], 1
  3436.         jz      @f
  3437.         mov     ebx, [esp]
  3438.         movzx   edi, byte [ecx+attributeOffset]
  3439.         add     edi, ecx
  3440.         add     edi, [ebx+4]
  3441.         mov     ecx, [ebx+12]
  3442.         mov     esi, [ebx+16]
  3443.         rep movsb
  3444. @@:
  3445.         mov     ebx, [ebp+NTFS.frs_buffer]
  3446.         mov     edx, [ebp+NTFS.mftLastRead]
  3447.         call    writeRecord     ; file
  3448.         call    ntfs_restore_usa_frs
  3449. .writeNode:
  3450.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3451.         mov     edx, [ebp+NTFS.nodeLastRead]
  3452.         call    writeRecord     ; directory
  3453.         pop     ebx
  3454.         mov     ecx, [ebp+NTFS.attr_offs]
  3455.         cmp     byte [ecx+nonResidentFlag], 0
  3456.         jz      .done
  3457.         mov     ecx, [ebx+12]
  3458.         test    ecx, ecx
  3459.         jz      .done
  3460.         mov     eax, [ebx+4]
  3461.         mov     edx, [ebx+8]
  3462.         mov     esi, [ebx+16]
  3463.         shrd    eax, edx, 9
  3464.         test    dword[ebx+4], 1FFh
  3465.         jz      .aligned
  3466.         mov     [ebp+NTFS.cur_offs], eax
  3467.         mov     [ebp+NTFS.cur_size], 1
  3468.         lea     edi, [ebp+NTFS.bitmap_buf]
  3469.         mov     [ebp+NTFS.cur_buf], edi
  3470.         call    ntfs_read_attr.continue
  3471.         jc      ntfsDevice
  3472.         mov     eax, [ebx+4]
  3473.         and     eax, 1FFh
  3474.         add     edi, eax
  3475.         sub     eax, [ebp+NTFS.cur_read]
  3476.         neg     eax
  3477.         push    ecx
  3478.         cmp     ecx, eax
  3479.         jb      @f
  3480.         mov     ecx, eax
  3481. @@:
  3482.         sub     [esp], ecx
  3483.         rep movsb
  3484.         push    ebx
  3485.         mov     eax, [ebp+NTFS.LastRead]
  3486.         lea     ebx, [ebp+NTFS.bitmap_buf]
  3487.         mov     ecx, 1
  3488.         xor     edx, edx
  3489.         call    fs_write64_app
  3490.         pop     ebx
  3491.         pop     ecx
  3492.         test    ecx, ecx
  3493.         jz      .done
  3494.         mov     eax, [ebx+4]
  3495.         mov     edx, [ebx+8]
  3496.         shrd    eax, edx, 9
  3497.         inc     eax
  3498. .aligned:
  3499.         push    ecx
  3500.         shr     ecx, 9
  3501.         mov     [ebp+NTFS.cur_offs], eax
  3502.         mov     [ebp+NTFS.cur_size], ecx
  3503.         mov     [ebp+NTFS.cur_buf], esi
  3504.         add     eax, ecx
  3505.         push    eax
  3506.         mov     [ebp+NTFS.bWriteAttr], 1
  3507.         call    ntfs_read_attr.continue
  3508.         mov     [ebp+NTFS.bWriteAttr], 0
  3509.         pop     [ebp+NTFS.cur_offs]
  3510.         pop     ecx
  3511.         jc      ntfsDevice
  3512.         and     ecx, 1FFh
  3513.         jz      .done
  3514.         add     esi, [ebp+NTFS.cur_read]
  3515.         mov     [ebp+NTFS.cur_size], 1
  3516.         lea     edi, [ebp+NTFS.bitmap_buf]
  3517.         mov     [ebp+NTFS.cur_buf], edi
  3518.         call    ntfs_read_attr.continue
  3519.         jc      ntfsDevice
  3520.         rep movsb
  3521.         push    ebx
  3522.         mov     eax, [ebp+NTFS.LastRead]
  3523.         lea     ebx, [ebp+NTFS.bitmap_buf]
  3524.         mov     ecx, 1
  3525.         xor     edx, edx
  3526.         call    fs_write64_app
  3527.         pop     ebx
  3528. .done:
  3529.         mov     ebx, [ebx+12]
  3530.         jmp     ntfsDone
  3531.  
  3532. ;----------------------------------------------------------------
  3533. ntfs_Delete:
  3534.         xor     ebx, ebx
  3535.         cmp     byte [esi], 0
  3536.         jnz     @f
  3537.         movi    eax, ERROR_ACCESS_DENIED
  3538.         ret
  3539.  
  3540. @@:
  3541.         call    ntfs_lock
  3542.         stdcall ntfs_find_lfn, [esp+4]
  3543.         jc      ntfsNotFound
  3544.         cmp     [ebp+NTFS.cur_iRecord], 16
  3545.         jc      ntfsDenied
  3546.         cmp     [ebp+NTFS.fragmentCount], 1
  3547.         jnz     ntfsUnsupported     ; record fragmented
  3548.         mov     edx, [ebp+NTFS.cur_iRecord]
  3549.         shr     edx, 3
  3550.         cmp     edx, [ebp+NTFS.mftBitmapSize]
  3551.         jnc     ntfsUnsupported
  3552.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  3553.         mov     byte [edx], 0
  3554.         mov     edx, [ebp+NTFS.LastRead]
  3555.         mov     [ebp+NTFS.nodeLastRead], edx
  3556.         test    byte [eax+indexFlags], 1
  3557.         jz      .deleteIndex    ; no subnode
  3558.         movzx   edx, word [eax+indexAllocatedSize]
  3559.         mov     edi, eax
  3560.         mov     eax, [eax+edx-8]
  3561.         mov     edx, [ebp+NTFS.cur_size]
  3562.         push    edx
  3563.         cmp     edx, [ebp+NTFS.cur_subnode_size]
  3564.         jz      @f
  3565.         mul     [ebp+NTFS.sectors_per_cluster]
  3566. @@:
  3567.         mov     [ebp+NTFS.cur_attr], 0xA0
  3568.         mov     [ebp+NTFS.cur_offs], eax
  3569.         push    eax
  3570.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3571.         mov     esi, ebx
  3572.         mov     [ebp+NTFS.cur_buf], ebx
  3573.         call    ntfs_read_attr.newAttribute
  3574.         pop     [ebp+NTFS.cur_offs]
  3575.         pop     eax
  3576.         jc      ntfsFail
  3577.         cmp     dword [esi], 'INDX'
  3578.         jnz     ntfsFail
  3579.         mov     [ebp+NTFS.cur_size], eax
  3580.         shl     eax, 9
  3581.         call    ntfs_restore_usa
  3582.         jc      ntfsFail
  3583.         add     esi, recordNode
  3584.         cmp     byte [esi+nonLeafFlag], 0
  3585.         jnz     ntfsUnsupported ; non leaf node
  3586.         add     esi, [esi+indexOffset]
  3587.         test    byte [esi+indexFlags], 2
  3588.         jnz     .deleteSubnode  ; empty node
  3589.         xor     eax, eax
  3590. @@:
  3591.         add     esi, eax
  3592.         mov     ax, [esi+indexAllocatedSize]
  3593.         test    byte [esi+eax+indexFlags], 2
  3594.         jz      @b
  3595.         movzx   edx, word [edi+indexAllocatedSize]
  3596.         sub     edx, eax
  3597.         sub     edx, 8
  3598.         mov     ebx, esi
  3599.         mov     eax, edi
  3600.         jmp     @f
  3601.  
  3602. .deleteSubnode:
  3603.         mov     esi, [ebp+NTFS.attr_offs]
  3604.         add     esi, [esi+sizeWithHeader]
  3605.         cmp     byte [esi], 0xB0
  3606.         jnz     ntfsFail
  3607.         movzx   eax, byte [esi+attributeOffset]
  3608.         add     esi, eax
  3609.         mov     eax, [ebp+NTFS.cur_offs]
  3610.         xor     edx, edx
  3611.         div     [ebp+NTFS.cur_size]
  3612.         mov     edx, eax
  3613.         shr     eax, 3
  3614.         and     edx, 7
  3615.         btr     [esi+eax], edx
  3616.         mov     dx, [edi+indexAllocatedSize]
  3617.         mov     eax, edi
  3618.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  3619.         mov     byte [edi], 0
  3620.         xor     ebx, ebx
  3621.         mov     esi, [ebp+NTFS.cur_index_buf]
  3622.         cmp     dword [esi], 'INDX'
  3623.         jnz     @f
  3624.         mov     esi, [ebp+NTFS.frs_buffer]
  3625.         mov     ecx, [esi+recordRealSize]
  3626.         shr     ecx, 2
  3627.         rep movsd
  3628.         jmp     @f
  3629.  
  3630. .deleteIndex:
  3631.         movzx   edx, word [eax+indexAllocatedSize]
  3632.         mov     ecx, [eax+fileRecordReference]
  3633.         cmp     [eax+edx+fileRecordReference], ecx
  3634.         jnz     @f
  3635.         add     dx, [eax+edx+indexAllocatedSize]
  3636. @@:
  3637.         mov     edi, [ebp+NTFS.cur_index_buf]
  3638.         cmp     dword [edi], 'INDX'
  3639.         jz      .indexRecord
  3640.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  3641.         mov     ecx, [esi+recordRealSize]
  3642.         shr     ecx, 2
  3643.         rep movsd
  3644.         mov     esi, [ebp+NTFS.cur_index_buf]
  3645.         mov     edi, [ebp+NTFS.indexRoot]
  3646.         sub     edi, [ebp+NTFS.frs_buffer]
  3647.         add     edi, esi
  3648.         sub     [edi+sizeWithHeader], edx
  3649.         sub     [edi+sizeWithoutHeader], edx
  3650.         mov     cl, [edi+attributeOffset]
  3651.         add     edi, ecx
  3652.         sub     [edi+rootNode+nodeRealSize], edx
  3653.         sub     [edi+rootNode+nodeAllocatedSize], edx
  3654.         sub     eax, esi
  3655.         add     eax, edi
  3656.         sub     [esi+recordRealSize], edx
  3657.         mov     ecx, [esi+recordRealSize]
  3658.         cmp     [esi+recordAllocatedSize], ecx
  3659.         jc      ntfsUnsupported
  3660.         jmp     @f
  3661.  
  3662. .indexRecord:
  3663.         add     edi, recordNode
  3664.         sub     [edi+nodeRealSize], edx
  3665.         mov     ecx, [edi+nodeRealSize]
  3666.         cmp     [edi+nodeAllocatedSize], ecx
  3667.         jc      ntfsUnsupported
  3668.         add     ecx, recordNode
  3669. @@:
  3670.         add     ecx, [ebp+NTFS.cur_index_buf]
  3671.         sub     ecx, eax
  3672.         mov     esi, eax
  3673.         add     esi, edx
  3674.         mov     edi, eax
  3675.         test    edx, edx
  3676.         jns     @f
  3677.         neg     edx
  3678.         add     edx, ecx
  3679.         sub     edx, 4
  3680.         add     esi, edx
  3681.         add     edi, edx
  3682.         std
  3683. @@:
  3684.         jz      @f
  3685.         shr     ecx, 2
  3686.         rep movsd
  3687.         cld
  3688. @@:
  3689.         test    ebx, ebx
  3690.         jz      @f
  3691. ; copy index from the subnode to replace deleted pointing index
  3692.         movzx   ecx, word [ebx+indexAllocatedSize]
  3693.         mov     edx, ecx
  3694.         shr     ecx, 2
  3695.         mov     esi, ebx
  3696.         mov     edi, eax
  3697.         rep movsd
  3698.         mov     edi, [ebp+NTFS.cur_index_buf]
  3699.         xchg    [ebp+NTFS.secondIndexBuffer], edi
  3700.         mov     [ebp+NTFS.cur_index_buf], edi
  3701.         add     word [eax+indexAllocatedSize], 8
  3702.         mov     byte [eax+indexFlags], 1
  3703.         mov     eax, [ebp+NTFS.LastRead]
  3704.         xchg    [ebp+NTFS.nodeLastRead], eax
  3705.         mov     [ebp+NTFS.rootLastRead], eax
  3706.         mov     eax, ebx
  3707.         xor     ebx, ebx
  3708.         jmp     .indexRecord
  3709.  
  3710. .ret:
  3711.         ret
  3712.  
  3713. @@:         ; examine file record
  3714.         mov     [ebp+NTFS.cur_attr], 0x80   ; file?
  3715.         mov     [ebp+NTFS.cur_offs], 0
  3716.         mov     [ebp+NTFS.cur_size], 0
  3717.         call    ntfs_read_attr
  3718.         jnc     @f
  3719.         mov     eax, [ebp+NTFS.cur_index_size]
  3720.         shl     eax, 9
  3721.         stdcall kernel_alloc, eax
  3722.         test    eax, eax
  3723.         jz      ntfsFail
  3724.         push    [ebp+NTFS.cur_index_buf]
  3725.         push    [ebp+NTFS.secondIndexBuffer]
  3726.         push    [ebp+NTFS.cur_index_size]
  3727.         mov     [ebp+NTFS.cur_index_buf], eax
  3728.         mov     [ebp+NTFS.secondIndexBuffer], eax
  3729.         xor     eax, eax
  3730.         push    eax eax eax eax
  3731.         mov     [esp+12], esp
  3732.         push    eax
  3733.         mov     ebx, esp
  3734.         mov     [ebp+NTFS.cur_attr], 0x90   ; folder?
  3735.         call    ntfs_ReadFolder.doit
  3736.         push    eax
  3737.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  3738.         pop     eax
  3739.         mov     edx, [esp+12]
  3740.         add     esp, 20
  3741.         pop     [ebp+NTFS.cur_index_size]
  3742.         pop     [ebp+NTFS.secondIndexBuffer]
  3743.         pop     [ebp+NTFS.cur_index_buf]
  3744.         test    eax, eax
  3745.         jnz     .ret
  3746.         cmp     edx, 2
  3747.         jnz     ntfsDenied      ; folder is not empty
  3748.         mov     [ebp+NTFS.cur_attr], 0xA0
  3749.         mov     [ebp+NTFS.cur_offs], 0
  3750.         mov     [ebp+NTFS.cur_size], 0
  3751.         call    ntfs_read_attr.newAttribute
  3752.         jc      .writeBitmapMFT
  3753. @@:
  3754.         mov     esi, [ebp+NTFS.frs_buffer]
  3755.         cmp     word [esi+baseRecordReuse], 0
  3756.         jnz     ntfsUnsupported     ; auxiliary record
  3757.         mov     esi, [ebp+NTFS.attr_offs]
  3758.         cmp     byte [esi+nonResidentFlag], 0
  3759.         jz      .writeBitmapMFT
  3760.         movzx   eax, byte [esi+dataRunsOffset]
  3761.         add     esi, eax
  3762.         xor     edi, edi
  3763.         sub     esp, 16
  3764. @@:
  3765.         call    ntfs_decode_mcb_entry
  3766.         jnc     @f
  3767.         cmp     dword[esp+8], 0
  3768.         jz      @b
  3769.         add     edi, [esp+8]
  3770.         mov     ebx, [esp]
  3771.         call    ntfsSpaceFree
  3772.         jnc     @b
  3773. @@:
  3774.         add     esp, 16
  3775. .writeBitmapMFT:    ; "delete" file record
  3776.         mov     eax, [ebp+NTFS.cur_iRecord]
  3777.         mov     ecx, eax
  3778.         shr     eax, 3
  3779.         and     ecx, 7
  3780.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  3781.         btr     [edi+eax], ecx
  3782.         shr     eax, 9
  3783.         mov     ebx, eax
  3784.         shl     ebx, 9
  3785.         add     eax, [ebp+NTFS.mftBitmapLocation]
  3786.         add     ebx, edi
  3787.         mov     ecx, 1
  3788.         xor     edx, edx
  3789.         call    fs_write64_sys
  3790.         mov     ebx, [ebp+NTFS.frs_buffer]
  3791.         mov     byte [ebx+recordFlags], 0
  3792.         mov     edx, [ebp+NTFS.mftLastRead]
  3793.         call    writeRecord
  3794. ; write directory node
  3795.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3796.         mov     edx, [ebp+NTFS.nodeLastRead]
  3797.         call    writeRecord
  3798.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3799.         cmp     byte [ebx], 0
  3800.         jz      ntfsDone
  3801.         mov     edx, [ebp+NTFS.rootLastRead]
  3802.         call    writeRecord
  3803.         jmp     ntfsDone
  3804.  
  3805. ;----------------------------------------------------------------
  3806. ntfs_SetFileEnd:
  3807.         cmp     byte [esi], 0
  3808.         jnz     @f
  3809.         xor     ebx, ebx
  3810.         movi    eax, ERROR_ACCESS_DENIED
  3811.         ret
  3812. @@:
  3813.         call    ntfs_lock
  3814.         stdcall ntfs_find_lfn, [esp+4]
  3815.         jc      ntfsNotFound
  3816.         cmp     [ebp+NTFS.cur_iRecord], 16
  3817.         jc      ntfsDenied
  3818.         bt      dword [eax+fileFlags], 28
  3819.         jc      ntfsDenied
  3820.         cmp     [ebp+NTFS.fragmentCount], 1
  3821.         jnz     ntfsUnsupported     ; record fragmented
  3822. ; edit directory node
  3823.         mov     edi, [ebp+NTFS.cur_index_buf]
  3824.         cmp     dword [edi], 'INDX'
  3825.         jz      @f
  3826.         mov     esi, [ebp+NTFS.frs_buffer]
  3827.         mov     ecx, [esi+recordRealSize]
  3828.         shr     ecx, 2
  3829.         rep movsd
  3830.         mov     esi, [ebp+NTFS.attr_offs]
  3831.         mov     cl, [esi+attributeOffset]
  3832.         sub     esi, [ebp+NTFS.frs_buffer]
  3833.         add     eax, ecx
  3834.         add     eax, esi
  3835. @@:
  3836.         mov     ecx, [ebx+4]
  3837.         mov     edx, [ebx+8]
  3838.         mov     [eax+fileRealSize], ecx
  3839.         mov     [eax+fileRealSize+4], edx
  3840.         mov     eax, [ebp+NTFS.LastRead]
  3841.         mov     [ebp+NTFS.nodeLastRead], eax
  3842.         mov     [ebp+NTFS.cur_attr], 0x80
  3843.         mov     [ebp+NTFS.cur_offs], 0
  3844.         mov     [ebp+NTFS.cur_size], 0
  3845.         call    ntfs_read_attr
  3846.         jc      ntfsFail
  3847.         mov     eax, ecx
  3848.         mov     ecx, [ebp+NTFS.frs_buffer]
  3849.         cmp     word [ecx+baseRecordReuse], 0
  3850.         jnz     ntfsUnsupported     ; auxiliary record
  3851.         mov     ecx, [ebp+NTFS.attr_offs]
  3852.         cmp     word [ecx+attributeFlags], 0
  3853.         jnz     ntfsUnsupported
  3854.         cmp     byte [ecx+nonResidentFlag], 0
  3855.         jz      .resizeAttribute
  3856.         cmp     [ecx+attributeRealSize+4], edx
  3857.         jnz     .resizeAttribute
  3858.         cmp     [ecx+attributeRealSize], eax
  3859.         jnc     .resizeAttribute
  3860.         mov     eax, [ecx+attributeRealSize]
  3861.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3862.         mov     [ebp+NTFS.cur_size], ecx
  3863.         shl     ecx, 9
  3864.         div     ecx
  3865.         test    edx, edx
  3866.         jz      .aligned
  3867.         push    edx
  3868.         push    ecx
  3869.         mul     [ebp+NTFS.sectors_per_cluster]
  3870.         mov     [ebp+NTFS.cur_offs], eax
  3871.         stdcall kernel_alloc, ecx
  3872.         pop     ecx
  3873.         pop     edi
  3874.         mov     esi, eax
  3875.         sub     ecx, edi
  3876.         add     edi, eax
  3877.         mov     [ebp+NTFS.cur_buf], eax
  3878.         call    ntfs_read_attr.continue
  3879.         jc      @f
  3880.         xor     eax, eax
  3881.         rep stosb
  3882.         push    ebx
  3883.         mov     eax, [ebp+NTFS.LastRead]
  3884.         mov     ebx, esi
  3885.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3886.         xor     edx, edx
  3887.         call    fs_write64_app
  3888.         pop     ebx
  3889. @@:
  3890.         stdcall kernel_free, esi
  3891. .aligned:
  3892.         mov     eax, [ebx+4]
  3893.         mov     edx, [ebx+8]
  3894. .resizeAttribute:
  3895.         call    resizeAttribute
  3896.         jc      ntfsError
  3897.         mov     ebx, [ebp+NTFS.frs_buffer]
  3898.         mov     edx, [ebp+NTFS.mftLastRead]
  3899.         call    writeRecord     ; file
  3900.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3901.         mov     edx, [ebp+NTFS.nodeLastRead]
  3902.         call    writeRecord     ; directory
  3903.         call    ntfsSpaceClean
  3904.         jmp     ntfsDone
  3905.  
  3906. ;----------------------------------------------------------------
  3907. ntfs_SetFileInfo:
  3908.         movi    eax, ERROR_UNSUPPORTED_FS
  3909.         ret
  3910.  
  3911. ;----------------------------------------------------------------
  3912. ntfs_GetFileInfo:
  3913.         cmp     byte [esi], 0
  3914.         jnz     @f
  3915.         movi    eax, ERROR_UNSUPPORTED_FS
  3916.         ret
  3917. @@:
  3918.         call    ntfs_lock
  3919.         stdcall ntfs_find_lfn, [esp+4]
  3920.         jnc     .found
  3921.         test    eax, eax
  3922.         jz      ntfsFail
  3923.         jmp     ntfsNotFound
  3924. .found:
  3925.         push    esi edi
  3926.         mov     esi, eax
  3927.         mov     edi, [ebx+16]
  3928.         xor     eax, eax
  3929.         call    ntfs_direntry_to_bdfe
  3930.         pop     edi esi
  3931.         call    ntfs_unlock
  3932.         xor     eax, eax
  3933.         ret
  3934.  
  3935. ntfsUnsupported:
  3936.         push    ERROR_UNSUPPORTED_FS
  3937.         jmp     ntfsOut
  3938. ntfsDevice:
  3939.         push    ERROR_DEVICE
  3940.         jmp     ntfsOut
  3941. ntfsNotFound:
  3942.         push    ERROR_FILE_NOT_FOUND
  3943.         jmp     ntfsOut
  3944. ntfsDenied:
  3945.         push    ERROR_ACCESS_DENIED
  3946.         jmp     ntfsOut
  3947. ntfsFail:
  3948.         push    ERROR_FS_FAIL
  3949.         jmp     ntfsOut
  3950. ntfsDiskFull:
  3951.         push    ERROR_DISK_FULL
  3952.         jmp     ntfsOut
  3953. ntfsErrorPop3:
  3954.         pop     ebx
  3955. ntfsErrorPop2:
  3956.         pop     ebx
  3957. ntfsErrorPop:
  3958.         pop     ebx
  3959. ntfsError:
  3960.         push    eax
  3961. ntfsOut:
  3962.         call    ntfs_unlock
  3963.         xor     ebx, ebx
  3964.         pop     eax
  3965.         ret
  3966.