Subversion Repositories Kolibri OS

Rev

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