Subversion Repositories Kolibri OS

Rev

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