Subversion Repositories Kolibri OS

Rev

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