Subversion Repositories Kolibri OS

Rev

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