1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
4 ;; Distributed under terms of the GNU General Public License. ;;
6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10 ; NTFS external functions
12 ; ebx -> parameter structure of sysfunc 70
13 ; ebp -> NTFS structure
14 ; esi -> path string in UTF-8
16 ; eax, ebx = return values for sysfunc 70
21 dd (ntfs_user_functions_end - ntfs_user_functions - 8) / 4
32 ntfs_user_functions_end:
36 ; File is a FileRecord in the $MFT.
37 ; $MFT is a file, that consists of FileRecords and starts with FileRecord of itself.
38 ; FileRecord (FILE) consists of a header and attributes.
39 ; Attribute consists of a header and a body.
40 ; Attribute's body can be inside (resident) or outside of FileRecord.
41 ; File's data is a body of $Data (80h) attribute.
42 ; FileRecords is a data of the $MFT file.
43 ; Directory is a file, that consists of index nodes.
44 ; Resident index node is always located in a body of $IndexRoot (90h) attribute.
45 ; Body of $IndexAllocation (A0h) attribute is always non resident
46 ; and consists of IndexRecords.
47 ; IndexRecord (INDX) consists of a header and an index node.
48 ; Index node consists of a header and indexes.
49 ; Index consists of a header and a copy of indexed attribute's body.
50 ; Directories index $Filename (30h) attribute of all existing files.
51 ; $IndexRoot and $IndexAllocation attributes of a directory has a name — $I30.
56 updateSequenceOffset = 4
57 updateSequenceSize = 6
64 recordAllocatedSize = 1ch
65 baseRecordReference = 20h ; for auxiliary records
76 ; resident attribute header
77 sizeWithoutHeader = 10h
80 ; non resident attribute header
84 attributeAllocatedSize = 28h
85 attributeRealSize = 30h
88 indexedAttributesType = 0
91 indexRecordSizeClus = 12 ; in sectors if less than one cluster
102 fileRecordReference = 0
103 fileReferenceReuse = 6
104 indexAllocatedSize = 8
107 directoryRecordReference = 16
108 directoryReferenceReuse = 16h
113 fileAllocatedSize = 38h
120 struct NTFS PARTITION
121 Lock MUTEX ; Currently operations with one partition
122 ; can not be executed in parallel since the legacy code is not ready.
123 sectors_per_cluster dd ?
124 mft_cluster dd ? ; location
125 mftmirr_cluster dd ? ; location
126 frs_size dd ? ; in bytes
127 frs_buffer dd ? ; MFT fileRecord buffer
128 mft_retrieval_end dd ?
129 mftSize dd ? ; in sectors
130 cur_index_size dd ? ; in sectors
131 cur_index_buf dd ? ; index node buffer
132 secondIndexBuffer dd ?
134 BitmapTotalSize dd ? ; bytes reserved
135 BitmapSize dd ? ; bytes readen
136 BitmapLocation dd ? ; starting sector
137 BitmapStart dd ? ; first byte after area, reserved for MFT
138 mftBitmapBuffer dd ? ; one cluster
139 mftBitmapSize dd ? ; bytes readen
140 mftBitmapLocation dd ? ; starting sector
145 attr_iBaseRecord dd ?
146 cur_attr dd ? ; attribute type
147 cur_iRecord dd ? ; number of fileRecord in MFT
148 cur_offs dd ? ; attribute VCN in sectors
149 cur_size dd ? ; max sectors to read
151 cur_read dd ? ; bytes readen
153 cur_subnode_size dd ?
154 LastRead dd ? ; last readen block of sectors
161 fileDataStart dd ? ; starting cluster
162 fileDataSize dd ? ; in clusters
164 fileRealSize dd ? ; in bytes
168 bWriteAttr db ? ; Warning: Don't forget to turn off!!!
171 align0 rb 1024-NTFS.align0
173 attrlist_mft_buf rb 1024
178 ; in: ebx -> buffer, edx = size of partition
179 ; out: CF=1 -> invalid
181 cmp dword [ebx+3], 'NTFS'
183 cmp dword [ebx+7], ' '
185 ; 2. Number of bytes per sector is the same as for physical device
186 ; (that is, 0x200 for hard disk)
187 cmp word [ebx+11], 0x200
189 ; 3. Number of sectors per cluster must be power of 2
190 movzx eax, byte [ebx+13]
195 ; 4. FAT parameters must be zero
198 cmp dword [ebx+16], 0
204 cmp dword [ebx+32], 0
206 ; 5. Number of sectors <= partition size
207 cmp dword [ebx+0x2C], 0
211 ; 6. $MFT and $MFTMirr clusters must be within partition
212 cmp dword [ebx+0x34], 0
215 movzx eax, byte [ebx+13]
222 cmp dword [ebx+0x3C], 0
225 movzx eax, byte [ebx+13]
232 ; 7. Clusters per FRS must be either power of 2 or between -31 and -9
233 movsx eax, byte [ebx+0x40]
242 @@: ; 8. Same for clusters per IndexAllocationBuffer
243 movsx eax, byte [ebx+0x44]
252 @@: ; OK, this is correct NTFS bootsector
255 .no: ; No, this bootsector isn't NTFS
259 ; Mount if it's a valid NTFS partition.
260 ntfs_create_partition:
262 ; ebp -> PARTITION structure
266 ; eax -> NTFS structure, 0 = not NTFS
267 cmp dword [esi+DISK.MediaInfo.SectorSize], 512
269 mov edx, dword [ebp+PARTITION.Length]
277 call ntfs_test_bootsec
286 call ntfs_test_bootsec
292 .ntfs_setup: ; By given bootsector, initialize some NTFS variables
293 stdcall kernel_alloc, 1000h
296 mov ecx, dword [ebp+PARTITION.FirstSector]
297 mov dword [eax+NTFS.FirstSector], ecx
298 mov ecx, dword [ebp+PARTITION.FirstSector+4]
299 mov dword [eax+NTFS.FirstSector+4], ecx
300 mov ecx, [ebp+PARTITION.Disk]
301 mov [eax+NTFS.Disk], ecx
302 mov [eax+NTFS.FSUserFunctions], ntfs_user_functions
303 mov [eax+NTFS.bWriteAttr], 0
307 lea ecx, [ebp+NTFS.Lock]
309 movzx eax, byte [ebx+13]
310 mov [ebp+NTFS.sectors_per_cluster], eax
312 mov dword [ebp+NTFS.Length], eax
313 and dword [ebp+NTFS.Length+4], 0
315 mov [ebp+NTFS.mft_cluster], eax
317 mov [ebp+NTFS.mftmirr_cluster], eax
318 movsx eax, byte [ebx+0x40]
321 mul [ebp+NTFS.sectors_per_cluster]
331 mov [ebp+NTFS.frs_size], eax
332 stdcall kernel_alloc, eax
335 mov [ebp+NTFS.frs_buffer], eax
336 ; read $MFT disposition
337 mov eax, [ebp+NTFS.mft_cluster]
338 mul [ebp+NTFS.sectors_per_cluster]
339 mov ecx, [ebp+NTFS.frs_size]
341 mov ebx, [ebp+NTFS.frs_buffer]
345 cmp dword [ebx], 'FILE'
347 call ntfs_restore_usa_frs
350 mov eax, [ebp+NTFS.mftmirr_cluster]
351 mul [ebp+NTFS.sectors_per_cluster]
352 mov ecx, [ebp+NTFS.frs_size]
354 mov ebx, [ebp+NTFS.frs_buffer]
358 cmp dword [ebx], 'FILE'
360 call ntfs_restore_usa_frs
362 .mftok: ; prepare $MFT retrieval information
363 ; search for unnamed non-resident $DATA attribute
364 movzx eax, word [ebx+attributeOffset]
369 cmp dword [eax], 0x80
371 cmp byte [eax+nameLength], 0
374 add eax, [eax+sizeWithHeader]
378 cmp byte [eax+nonResidentFlag], 0
380 movzx esi, word [eax+dataRunsOffset]
382 mov edx, [eax+attributeAllocatedSize+4]
383 mov eax, [eax+attributeAllocatedSize]
385 mov [ebp+NTFS.mftSize], eax
387 lea ecx, [ebp+NTFS.mft_retrieval]
389 .scanmcb: ; load descriptions of fragments
390 call ntfs_decode_mcb_entry
392 mov eax, [esp] ; block length
394 add edx, [esp+8] ; block addr
401 lea eax, [ebp+NTFS.attrlist_buf]
406 mov [ebp+NTFS.mft_retrieval_end], eax
407 ; allocate index buffers
408 stdcall kernel_alloc, 2000h
411 mov [ebp+NTFS.cur_index_buf], eax
413 mov [ebp+NTFS.secondIndexBuffer], eax
414 mov [ebp+NTFS.cur_index_size], 8
415 ; reserve adress space for bitmap buffer and load some part of bitmap
416 mov eax, dword [ebp+NTFS.Length]
418 div [ebp+NTFS.sectors_per_cluster]
420 mov [ebp+NTFS.BitmapTotalSize], eax
424 call alloc_kernel_space
427 mov [ebp+NTFS.BitmapBuffer], eax
428 mov [ebp+NTFS.cur_buf], eax
429 mov eax, [ebp+NTFS.BitmapTotalSize]
430 add eax, [ebp+NTFS.mft_cluster]
431 shr eax, 3+2 ; reserve 1/8 of partition for $MFT
433 mov [ebp+NTFS.BitmapStart], eax
440 mov [ebp+NTFS.cur_size], eax
446 mov ebx, [ebp+NTFS.BitmapBuffer]
448 mov [ebp+NTFS.cur_iRecord], 6
449 mov [ebp+NTFS.cur_attr], 0x80
450 mov [ebp+NTFS.cur_offs], 0
453 mov eax, [ebp+NTFS.cur_read]
454 mov [ebp+NTFS.BitmapSize], eax
455 mov eax, [ebp+NTFS.LastRead]
456 mov [ebp+NTFS.BitmapLocation], eax
457 ; read MFT $BITMAP attribute
458 mov eax, [ebp+NTFS.sectors_per_cluster]
459 mov [ebp+NTFS.cur_size], eax
461 stdcall kernel_alloc, eax
464 mov [ebp+NTFS.mftBitmapBuffer], eax
465 mov [ebp+NTFS.cur_buf], eax
466 mov [ebp+NTFS.cur_iRecord], 0
467 mov [ebp+NTFS.cur_attr], 0xB0
468 mov [ebp+NTFS.cur_offs], 0
470 mov eax, [ebp+NTFS.cur_read]
472 jc .failFreeBitmapMFT
473 mov ecx, [ebp+NTFS.attr_offs]
474 cmp byte [ecx+nonResidentFlag], 1
475 jnz .failFreeBitmapMFT
476 mov [ebp+NTFS.mftBitmapSize], eax
477 mov eax, [ebp+NTFS.LastRead]
478 mov [ebp+NTFS.mftBitmapLocation], eax
491 stdcall kernel_free, [ebp+NTFS.mftBitmapBuffer]
493 stdcall kernel_free, [ebp+NTFS.BitmapBuffer]
495 mov eax, [ebp+NTFS.cur_index_buf]
496 cmp eax, [ebp+NTFS.secondIndexBuffer]
498 mov eax, [ebp+NTFS.secondIndexBuffer]
500 stdcall kernel_free, eax
502 stdcall kernel_free, [ebp+NTFS.frs_buffer]
504 stdcall kernel_free, ebp
511 stdcall kernel_free, [ebx+NTFS.frs_buffer]
512 stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
513 stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
514 mov eax, [ebx+NTFS.cur_index_buf]
515 cmp eax, [ebx+NTFS.secondIndexBuffer]
517 mov eax, [ebx+NTFS.secondIndexBuffer]
519 stdcall kernel_free, eax
520 stdcall kernel_free, ebx
525 lea ecx, [ebp+NTFS.Lock]
529 lea ecx, [ebp+NTFS.Lock]
533 ; [ebp+NTFS.bWriteAttr]=1 -> write attribute
535 ; [ebp+NTFS.cur_iRecord] = number of fileRecord
536 ; [ebp+NTFS.cur_attr] = attribute type
537 ; [ebp+NTFS.cur_offs] = attribute VCN in sectors
538 ; [ebp+NTFS.cur_buf] -> buffer for data
539 ; [ebp+NTFS.cur_size] = max sectors to read
541 ; [ebp+NTFS.cur_read] = bytes readen
542 ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
545 and [ebp+NTFS.cur_read], 0
546 cmp [ebp+NTFS.cur_iRecord], 0
548 cmp [ebp+NTFS.cur_attr], 0x80
550 ; precalculated part of $Mft $DATA
551 mov eax, [ebp+NTFS.cur_offs]
553 div [ebp+NTFS.sectors_per_cluster]
555 mov [ebp+NTFS.fragmentCount], 0
556 ; eax = VCN, ebx = offset in sectors from beginning of cluster
557 lea esi, [ebp+NTFS.mft_retrieval]
561 cmp esi, [ebp+NTFS.mft_retrieval_end]
569 mul [ebp+NTFS.sectors_per_cluster]
571 mul [ebp+NTFS.sectors_per_cluster]
574 mov ebx, [ebp+NTFS.cur_buf]
575 cmp ecx, [ebp+NTFS.cur_size]
577 mov ecx, [ebp+NTFS.cur_size]
579 mov [ebp+NTFS.LastRead], eax
584 sub [ebp+NTFS.cur_size], edi
585 add [ebp+NTFS.cur_offs], edi
587 add [ebp+NTFS.cur_read], edi
588 add [ebp+NTFS.cur_buf], edi
589 inc [ebp+NTFS.fragmentCount]
592 cmp [ebp+NTFS.cur_size], eax
609 ; 1. Read file record.
610 ; N.B. This will do recursive call of read_attr for $MFT::$Data.
611 mov eax, [ebp+NTFS.cur_iRecord]
612 and [ebp+NTFS.attr_list], 0
613 or dword [ebp+NTFS.attr_size+4], -1
614 or [ebp+NTFS.attr_iBaseRecord], -1
615 call ntfs_read_file_record
617 ; 2. Find required attribute.
618 mov eax, [ebp+NTFS.frs_buffer]
619 ; a) For auxiliary records, read base record.
620 ; If base record is present, base iRecord may be 0 (for $Mft),
621 ; but SequenceNumber is nonzero.
622 cmp word [eax+baseRecordReuse], 0
624 mov eax, [eax+baseRecordReference]
626 call ntfs_read_file_record
632 and [ebp+NTFS.cur_read], 0
634 ; b) Scan for required attribute and for $ATTR_LIST
635 mov eax, [ebp+NTFS.frs_buffer]
636 movzx ecx, word [eax+attributeOffset]
638 mov ecx, [ebp+NTFS.cur_attr]
639 and [ebp+NTFS.attr_offs], 0
645 cmp [ebp+NTFS.attr_iBaseRecord], -1
647 cmp dword [eax], 0x20 ; $ATTR_LIST
649 mov [ebp+NTFS.attr_list], eax
653 ; ignore named $DATA attributes (aka NTFS streams)
656 cmp byte [eax+nameLength], 0
659 mov [ebp+NTFS.attr_offs], eax
661 add eax, [eax+sizeWithHeader]
666 and [ebp+NTFS.cur_read], 0
668 ; c) Check for required offset and length
669 mov ecx, [ebp+NTFS.attr_offs]
671 push [ebp+NTFS.cur_size]
672 push [ebp+NTFS.cur_read]
677 cmp [ebp+NTFS.bCanContinue], 0
679 sub edx, [ebp+NTFS.cur_read]
683 mov [ebp+NTFS.cur_size], ecx
686 cmp [ebp+NTFS.cur_attr], 0x20
688 mov ecx, [ebp+NTFS.attr_list]
691 and dword [esp+28], 0
692 cmp [ebp+NTFS.attr_offs], 1 ; define CF
698 ; required attribute or required offset was not found in base record;
699 ; it may be present in auxiliary records;
701 mov eax, [ebp+NTFS.attr_iBaseRecord]
704 call ntfs_read_file_record
706 or [ebp+NTFS.attr_iBaseRecord], -1
708 push [ebp+NTFS.cur_offs]
709 push [ebp+NTFS.cur_size]
710 push [ebp+NTFS.cur_read]
711 push [ebp+NTFS.cur_buf]
712 push dword [ebp+NTFS.attr_size]
713 push dword [ebp+NTFS.attr_size+4]
714 or dword [ebp+NTFS.attr_size+4], -1
715 and [ebp+NTFS.cur_offs], 0
716 mov [ebp+NTFS.cur_size], 2
717 and [ebp+NTFS.cur_read], 0
718 lea eax, [ebp+NTFS.attrlist_buf]
719 cmp [ebp+NTFS.cur_iRecord], 0
721 lea eax, [ebp+NTFS.attrlist_mft_buf]
723 mov [ebp+NTFS.cur_buf], eax
728 pop dword [ebp+NTFS.attr_size+4]
729 pop dword [ebp+NTFS.attr_size]
730 mov ecx, [ebp+NTFS.cur_read]
731 pop [ebp+NTFS.cur_buf]
732 pop [ebp+NTFS.cur_read]
733 pop [ebp+NTFS.cur_size]
734 pop [ebp+NTFS.cur_offs]
737 lea ecx, [ecx+esi-1Ah]
740 mov eax, [ebp+NTFS.cur_attr]
747 movzx ecx, word [esi+4]
752 ; ignore named $DATA attributes (aka NTFS streams)
762 cmp dword [ebp+NTFS.attr_size+4], -1
764 ; if attribute is in auxiliary records, its size is defined only in first
766 call ntfs_read_file_record
768 mov eax, [ebp+NTFS.frs_buffer]
769 movzx ecx, word [eax+14h]
771 mov ecx, [ebp+NTFS.cur_attr]
790 mov dword [ebp+NTFS.attr_size], eax
791 and dword [ebp+NTFS.attr_size+4], 0
796 mov dword [ebp+NTFS.attr_size], ecx
798 mov dword [ebp+NTFS.attr_size+4], ecx
802 imul eax, [ebp+NTFS.sectors_per_cluster]
803 cmp eax, [ebp+NTFS.cur_offs]
806 mov edi, [esi+10h] ; keep previous iRecord
814 mov eax, [ebp+NTFS.cur_iRecord]
815 mov [ebp+NTFS.attr_iBaseRecord], eax
822 sub ecx, NTFS.attrlist_buf-1Ah
823 cmp [ebp+NTFS.cur_iRecord], 0
825 sub ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
831 lea esi, [ebp+NTFS.attrlist_buf+0x200]
832 lea edi, [ebp+NTFS.attrlist_buf]
833 cmp [ebp+NTFS.cur_iRecord], 0
835 lea esi, [ebp+NTFS.attrlist_mft_buf+0x200]
836 lea edi, [ebp+NTFS.attrlist_mft_buf]
843 push [ebp+NTFS.cur_offs]
844 push [ebp+NTFS.cur_size]
845 push [ebp+NTFS.cur_read]
846 push [ebp+NTFS.cur_buf]
847 push dword [ebp+NTFS.attr_size]
848 push dword [ebp+NTFS.attr_size+4]
849 or dword [ebp+NTFS.attr_size+4], -1
850 mov [ebp+NTFS.cur_offs], edx
851 mov [ebp+NTFS.cur_size], 1
852 and [ebp+NTFS.cur_read], 0
853 mov [ebp+NTFS.cur_buf], eax
854 mov ecx, [ebp+NTFS.attr_list]
858 mov ecx, [ebp+NTFS.cur_read]
859 pop dword [ebp+NTFS.attr_size+4]
860 pop dword [ebp+NTFS.attr_size]
861 pop [ebp+NTFS.cur_buf]
862 pop [ebp+NTFS.cur_read]
863 pop [ebp+NTFS.cur_size]
864 pop [ebp+NTFS.cur_offs]
866 lea ecx, [ecx+ebp+NTFS.attrlist_buf+0x200-0x1A]
867 cmp [ebp+NTFS.cur_iRecord], 0
869 add ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
873 mov [ebp+NTFS.bCanContinue], 0
874 cmp byte [ecx+nonResidentFlag], 0
876 mov eax, [ecx+sizeWithoutHeader]
878 mov edx, [ebp+NTFS.cur_offs]
884 movzx eax, word [ecx+attributeOffset]
886 add edx, ecx ; edx -> data
887 mov eax, [ebp+NTFS.cur_size]
888 cmp eax, (0xFFFFFFFF shr 9)+1
890 mov eax, (0xFFFFFFFF shr 9)+1
897 ; eax = length, edx -> data
898 mov [ebp+NTFS.cur_read], eax
901 mov ebx, [ebp+NTFS.cur_buf]
903 and [ebp+NTFS.cur_size], 0 ; CF=0
907 ; Not all auxiliary records contain correct FileSize info
908 mov eax, dword [ebp+NTFS.attr_size]
909 mov edx, dword [ebp+NTFS.attr_size+4]
912 mov eax, [ecx+attributeRealSize]
913 mov edx, [ecx+attributeRealSize+4]
914 mov dword [ebp+NTFS.attr_size], eax
915 mov dword [ebp+NTFS.attr_size+4], edx
920 sub eax, [ebp+NTFS.cur_offs]
922 ; return with nothing read
923 and [ebp+NTFS.cur_size], 0
930 and [ebp+NTFS.cur_tail], 0
931 cmp [ebp+NTFS.cur_size], eax
933 mov [ebp+NTFS.cur_size], eax
934 mov eax, dword [ebp+NTFS.attr_size]
936 mov [ebp+NTFS.cur_tail], eax
938 mov eax, [ebp+NTFS.cur_offs]
940 div [ebp+NTFS.sectors_per_cluster]
941 sub eax, [ecx+firstVCN]
944 ; eax = starting cluster, ebx = sector in the cluster
945 cmp [ebp+NTFS.cur_attr], 0x80
947 cmp [ebp+NTFS.cur_iRecord], 0
950 cmp [ebp+NTFS.bWriteAttr], 1
952 mov dword[esp], fs_write64_app
959 movzx esi, word [ecx+dataRunsOffset]
962 mov [ebp+NTFS.fragmentCount], 0
964 call ntfs_decode_mcb_entry
973 mul [ebp+NTFS.sectors_per_cluster]
975 mul [ebp+NTFS.sectors_per_cluster]
978 mov ebx, [ebp+NTFS.cur_buf]
979 cmp ecx, [ebp+NTFS.cur_size]
981 mov ecx, [ebp+NTFS.cur_size]
983 mov [ebp+NTFS.LastRead], eax
989 sub [ebp+NTFS.cur_size], ecx
990 add [ebp+NTFS.cur_offs], ecx
992 add [ebp+NTFS.cur_read], ecx
993 add [ebp+NTFS.cur_buf], ecx
994 inc [ebp+NTFS.fragmentCount]
997 cmp [ebp+NTFS.cur_size], 0
1000 mov eax, [ebp+NTFS.cur_tail]
1004 add [ebp+NTFS.cur_read], eax
1016 mov [ebp+NTFS.bCanContinue], 1
1019 ntfs_read_file_record:
1021 ; out: [ebp+NTFS.frs_buffer] -> file record
1022 ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
1023 ; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
1025 mov ecx, [ebp+NTFS.frs_size]
1030 push [ebp+NTFS.attr_iBaseRecord]
1031 push [ebp+NTFS.attr_offs]
1032 push [ebp+NTFS.attr_list]
1033 push dword [ebp+NTFS.attr_size+4]
1034 push dword [ebp+NTFS.attr_size]
1035 push [ebp+NTFS.cur_iRecord]
1036 push [ebp+NTFS.cur_attr]
1037 push [ebp+NTFS.cur_offs]
1038 push [ebp+NTFS.cur_size]
1039 push [ebp+NTFS.cur_buf]
1040 push [ebp+NTFS.cur_read]
1041 mov [ebp+NTFS.cur_attr], 0x80 ; $DATA
1042 and [ebp+NTFS.cur_iRecord], 0 ; $Mft
1043 mov [ebp+NTFS.cur_offs], eax
1045 mov [ebp+NTFS.cur_size], ecx
1046 mov eax, [ebp+NTFS.frs_buffer]
1047 mov [ebp+NTFS.cur_buf], eax
1049 mov edx, [ebp+NTFS.cur_read]
1050 pop [ebp+NTFS.cur_read]
1051 pop [ebp+NTFS.cur_buf]
1052 pop [ebp+NTFS.cur_size]
1053 pop [ebp+NTFS.cur_offs]
1054 pop [ebp+NTFS.cur_attr]
1055 pop [ebp+NTFS.cur_iRecord]
1056 pop dword [ebp+NTFS.attr_size]
1057 pop dword [ebp+NTFS.attr_size+4]
1058 pop [ebp+NTFS.attr_list]
1059 pop [ebp+NTFS.attr_offs]
1060 pop [ebp+NTFS.attr_iBaseRecord]
1062 cmp edx, [ebp+NTFS.frs_size]
1064 mov eax, [ebp+NTFS.LastRead]
1065 mov [ebp+NTFS.mftLastRead], eax
1066 mov eax, [ebp+NTFS.frs_buffer]
1067 cmp dword [eax], 'FILE'
1071 call ntfs_restore_usa_frs
1084 ntfs_restore_usa_frs:
1085 mov eax, [ebp+NTFS.frs_size]
1089 ; eax = size in bytes
1094 cmp [ebx+updateSequenceSize], ax
1096 movzx eax, word [ebx+updateSequenceOffset]
1100 lea edi, [ebx+0x1FE]
1117 ntfs_decode_mcb_entry:
1120 ; esp -> buffer (16 bytes)
1122 ; esi -> next MCB entry
1123 ; esp -> data run size
1124 ; esp+8 -> cluster (delta)
1141 cmp byte [esi-1], 80h
1155 cmp byte [esi-1], 80h
1165 ; in: esi -> path string in UTF-8
1167 ; [ebp+NTFS.cur_iRecord] = target fileRecord
1168 ; eax -> target index in the node
1169 ; [ebp+NTFS.LastRead] = target node location
1170 ; [ebp+NTFS.indexPointer] -> index, that points the target subnode
1171 ; [ebp+NTFS.nodeLastRead] = branch node location
1172 ; [ebp+NTFS.indexRoot] -> attribute
1173 ; [ebp+NTFS.rootLastRead] = directory fileRecord location
1174 ; [ebp+NTFS.cur_size] = index record size in sectors
1175 ; [ebp+NTFS.cur_subnode_size] = index record size in clusters or sectors
1176 ; CF=1 -> file not found, eax=0 -> error
1177 mov [ebp+NTFS.cur_iRecord], 5 ; start from root directory
1179 mov [ebp+NTFS.cur_attr], 0x90 ; $INDEX_ROOT
1180 and [ebp+NTFS.cur_offs], 0
1181 mov eax, [ebp+NTFS.cur_index_size]
1182 mov [ebp+NTFS.cur_size], eax
1183 mov eax, [ebp+NTFS.cur_index_buf]
1184 mov [ebp+NTFS.cur_buf], eax
1188 cmp [ebp+NTFS.cur_read], 0x20
1192 mov esi, [ebp+NTFS.cur_index_buf]
1193 mov eax, [esi+indexRecordSize]
1195 cmp [ebp+NTFS.cur_index_size], eax
1197 mov [ebp+NTFS.cur_size], eax
1198 mov al, [esi+indexRecordSizeClus]
1199 mov [ebp+NTFS.cur_subnode_size], eax
1201 mov eax, [esi+nodeRealSize]
1203 cmp [ebp+NTFS.cur_read], eax
1205 mov eax, [ebp+NTFS.mftLastRead]
1206 mov [ebp+NTFS.rootLastRead], eax
1207 mov eax, [ebp+NTFS.attr_offs]
1208 mov [ebp+NTFS.indexRoot], eax
1209 .scanloop: ; esi -> current index node
1210 add esi, [esi+indexOffset]
1213 test byte [esi+indexFlags], 2
1215 movzx ecx, byte [esi+fileNameLength]
1216 lea edi, [esi+fileName]
1239 movzx eax, word [esi+indexAllocatedSize]
1245 mov eax, [esi+indexRecordSize]
1247 stdcall kernel_alloc, eax
1250 mov edx, [ebp+NTFS.cur_index_buf]
1251 cmp edx, [ebp+NTFS.secondIndexBuffer]
1253 mov edx, [ebp+NTFS.secondIndexBuffer]
1255 mov [ebp+NTFS.cur_index_buf], eax
1256 add eax, [esi+indexRecordSize]
1257 mov [ebp+NTFS.secondIndexBuffer], eax
1258 mov [ebp+NTFS.cur_index_size], edi
1259 stdcall kernel_free, edx
1276 test byte [esi+indexFlags], 1
1278 mov eax, [ebp+NTFS.LastRead]
1279 mov [ebp+NTFS.nodeLastRead], eax
1280 mov [ebp+NTFS.indexPointer], esi
1281 movzx eax, word [esi+indexAllocatedSize]
1282 mov eax, [esi+eax-8]
1283 mov edx, [ebp+NTFS.cur_size]
1285 cmp edx, [ebp+NTFS.cur_subnode_size]
1287 mul [ebp+NTFS.sectors_per_cluster]
1289 mov esi, [ebp+NTFS.cur_index_buf]
1290 xchg [ebp+NTFS.secondIndexBuffer], esi
1291 mov [ebp+NTFS.cur_index_buf], esi
1292 mov [ebp+NTFS.cur_buf], esi
1293 mov [ebp+NTFS.cur_attr], 0xA0 ; $INDEX_ALLOCATION
1294 mov [ebp+NTFS.cur_offs], eax
1295 call ntfs_read_attr.newAttribute
1297 mov [ebp+NTFS.cur_size], eax
1299 cmp [ebp+NTFS.cur_read], eax
1301 cmp dword [esi], 'INDX'
1304 call ntfs_restore_usa
1313 mov eax, [eax+fileRecordReference]
1314 mov [ebp+NTFS.cur_iRecord], eax
1321 ;----------------------------------------------------------------
1326 mov [ebp+NTFS.cur_attr], 0x80 ; $DATA
1327 and [ebp+NTFS.cur_offs], 0
1328 and [ebp+NTFS.cur_size], 0
1333 cmp dword [ebx+8], 0x200
1344 mov [ebp+NTFS.cur_offs], eax
1345 mov [ebp+NTFS.cur_size], 1
1346 lea eax, [ebp+NTFS.bitmap_buf]
1347 mov [ebp+NTFS.cur_buf], eax
1348 call ntfs_read_attr.continue
1351 lea esi, [ebp+NTFS.bitmap_buf+eax]
1352 sub eax, [ebp+NTFS.cur_read]
1367 cmp [ebp+NTFS.cur_read], 0x200
1377 mov [ebp+NTFS.cur_offs], eax
1378 mov [ebp+NTFS.cur_buf], edx
1381 mov [ebp+NTFS.cur_size], eax
1382 add eax, [ebp+NTFS.cur_offs]
1384 call ntfs_read_attr.continue
1385 pop [ebp+NTFS.cur_offs]
1386 mov eax, [ebp+NTFS.cur_read]
1390 cmp [ebp+NTFS.cur_read], eax
1394 add edx, [ebp+NTFS.cur_read]
1395 mov [ebp+NTFS.cur_size], 1
1396 lea eax, [ebp+NTFS.bitmap_buf]
1397 mov [ebp+NTFS.cur_buf], eax
1398 call ntfs_read_attr.continue
1399 cmp [ebp+NTFS.cur_read], ecx
1401 mov [ebp+NTFS.cur_read], ecx
1403 xchg ecx, [ebp+NTFS.cur_read]
1406 lea esi, [ebp+NTFS.bitmap_buf]
1410 cmp ecx, [ebp+NTFS.cur_read]
1420 push ERROR_END_OF_FILE
1423 ;----------------------------------------------------------------
1426 mov [ebp+NTFS.cur_iRecord], 5 ; root directory
1432 mov [ebp+NTFS.cur_attr], 0x10 ; $STANDARD_INFORMATION
1433 and [ebp+NTFS.cur_offs], 0
1434 mov [ebp+NTFS.cur_size], 1
1435 lea eax, [ebp+NTFS.bitmap_buf]
1436 mov [ebp+NTFS.cur_buf], eax
1439 mov [ebp+NTFS.cur_attr], 0x90 ; $INDEX_ROOT
1441 mov eax, [ebp+NTFS.cur_index_size]
1442 mov [ebp+NTFS.cur_size], eax
1443 mov eax, [ebp+NTFS.cur_index_buf]
1444 mov [ebp+NTFS.cur_buf], eax
1445 call ntfs_read_attr.newAttribute
1447 cmp [ebp+NTFS.cur_read], 0x20
1449 mov esi, [ebp+NTFS.cur_index_buf]
1450 mov eax, [esi+indexRecordSize]
1452 cmp [ebp+NTFS.cur_index_size], eax
1454 mov [ebp+NTFS.cur_subnode_size], eax
1456 mov eax, [esi+nodeRealSize]
1458 cmp [ebp+NTFS.cur_read], eax
1463 pushd [ebx+8] ; read ANSI/UNICODE name
1472 mov [edi], eax ; version
1474 ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
1475 ; ecx = number of blocks to read
1476 ; edx -> parameters block: dd <output>, dd <flags>
1477 cmp [ebp+NTFS.cur_iRecord], 5
1479 ; dot and dotdot entries
1482 call .add_special_entry
1484 call .add_special_entry
1487 ; at first, dump index root
1488 add esi, [esi+indexOffset]
1490 test byte [esi+indexFlags], 2
1493 movzx eax, word [esi+indexAllocatedSize]
1499 mov eax, [esi+indexRecordSize]
1501 stdcall kernel_alloc, eax
1504 mov edx, [ebp+NTFS.cur_index_buf]
1505 cmp edx, [ebp+NTFS.secondIndexBuffer]
1507 mov edx, [ebp+NTFS.secondIndexBuffer]
1509 mov [ebp+NTFS.cur_index_buf], eax
1510 add eax, [esi+indexRecordSize]
1511 mov [ebp+NTFS.secondIndexBuffer], eax
1512 mov [ebp+NTFS.cur_index_size], edi
1513 stdcall kernel_free, edx
1517 ; now dump all subnodes
1519 lea edi, [ebp+NTFS.bitmap_buf]
1520 mov [ebp+NTFS.cur_buf], edi
1524 mov [ebp+NTFS.cur_attr], 0xB0 ; $BITMAP
1525 and [ebp+NTFS.cur_offs], 0
1526 mov [ebp+NTFS.cur_size], 2
1527 call ntfs_read_attr.newAttribute
1529 push 0 ; save offset in $BITMAP attribute
1530 and [ebp+NTFS.cur_offs], 0
1532 mov [ebp+NTFS.cur_attr], 0xA0
1533 mov eax, [ebp+NTFS.cur_subnode_size]
1534 mov [ebp+NTFS.cur_size], eax
1535 mov esi, [ebp+NTFS.cur_index_buf]
1536 mov [ebp+NTFS.cur_buf], esi
1537 mov eax, [ebp+NTFS.cur_offs]
1539 imul eax, [ebp+NTFS.cur_subnode_size]
1540 mov [ebp+NTFS.cur_offs], eax
1541 call ntfs_read_attr.newAttribute
1542 pop [ebp+NTFS.cur_offs]
1543 mov eax, [ebp+NTFS.cur_subnode_size]
1545 cmp [ebp+NTFS.cur_read], eax
1548 mov eax, [ebp+NTFS.cur_offs]
1550 bt dword [ebp+NTFS.bitmap_buf], eax
1552 jnc .dump_subnode_done
1553 cmp dword [esi], 'INDX'
1554 jnz .dump_subnode_done
1557 call ntfs_restore_usa
1559 jc .dump_subnode_done
1561 add esi, [esi+indexOffset]
1563 test byte [esi+indexFlags], 2
1564 jnz .dump_subnode_done
1566 movzx eax, word [esi+indexAllocatedSize]
1571 inc [ebp+NTFS.cur_offs]
1572 test [ebp+NTFS.cur_offs], 0x400*8-1
1574 mov [ebp+NTFS.cur_attr], 0xB0
1576 lea edi, [ebp+NTFS.bitmap_buf]
1577 mov [ebp+NTFS.cur_buf], edi
1583 push [ebp+NTFS.cur_offs]
1585 mov [ebp+NTFS.cur_offs], eax
1586 mov [ebp+NTFS.cur_size], 2
1588 call ntfs_read_attr.newAttribute
1590 pop [ebp+NTFS.cur_offs]
1605 mov al, ERROR_END_OF_FILE
1614 inc dword [eax+8] ; new file found
1619 inc dword [eax+4] ; new file block copied
1626 mov eax, dword [ebp+NTFS.bitmap_buf]
1627 mov edx, dword [ebp+NTFS.bitmap_buf+4]
1628 call ntfs_datetime_to_bdfe
1629 mov eax, dword [ebp+NTFS.bitmap_buf+0x18]
1630 mov edx, dword [ebp+NTFS.bitmap_buf+0x1C]
1631 call ntfs_datetime_to_bdfe
1632 mov eax, dword [ebp+NTFS.bitmap_buf+8]
1633 mov edx, dword [ebp+NTFS.bitmap_buf+0xC]
1634 call ntfs_datetime_to_bdfe
1642 cmp dword[edi-36], 2
1647 cmp dword[edi-36], 3
1662 ; do not return DOS 8.3 names
1663 cmp byte [esi+namespace], 2
1665 ; do not return system files
1666 cmp dword[esi+fileRecordReference], 16
1668 cmp byte [esi+fileNameLength], 0
1671 inc dword [eax+8] ; new file found
1676 inc dword [eax+4] ; new file block copied
1677 mov eax, [edx+4] ; flags
1678 call ntfs_direntry_to_bdfe
1680 movzx ecx, byte [esi+fileNameLength]
1682 cmp dword[edi-36], 2
1684 cmp dword[edi-36], 3
1718 ntfs_direntry_to_bdfe:
1719 mov [edi+4], eax ; ANSI/UNICODE name
1720 mov eax, [esi+fileFlags]
1721 test eax, 0x10000000
1723 and eax, not 0x10000000
1729 mov eax, [esi+fileCreated]
1730 mov edx, [esi+fileCreated+4]
1731 call ntfs_datetime_to_bdfe
1732 mov eax, [esi+fileAccessed]
1733 mov edx, [esi+fileAccessed+4]
1734 call ntfs_datetime_to_bdfe
1735 mov eax, [esi+fileModified]
1736 mov edx, [esi+fileModified+4]
1737 call ntfs_datetime_to_bdfe
1739 mov eax, [esi+fileRealSize]
1741 mov eax, [esi+fileRealSize+4]
1745 ntfs_datetime_to_bdfe:
1746 ; in: edx:eax = seconds since 01.01.1601 x10000000
1759 ;----------------------------------------------------------------
1774 call ntfs_direntry_to_bdfe
1782 mov eax, dword [ebp+NTFS.Length]
1783 mov edx, dword [ebp+NTFS.Length+4]
1795 mov [ebp+NTFS.cur_buf], edi
1796 mov [ebp+NTFS.cur_iRecord], 3
1797 mov [ebp+NTFS.cur_attr], 0x60
1798 mov [ebp+NTFS.cur_offs], 0
1799 mov [ebp+NTFS.cur_size], 1
1802 mov ecx, [ebp+NTFS.cur_read]
1812 call UTF16to8_string
1824 ;----------------------------------------------------------------
1826 mov [ebp+NTFS.bFolder], 1
1830 mov [ebp+NTFS.bFolder], 0
1831 @@: ; 1. Search file
1836 cmp [ebp+NTFS.cur_iRecord], 16
1838 cmp [ebp+NTFS.bFolder], 1
1840 test byte [eax+fileFlags], 1
1842 cmp [ebp+NTFS.fragmentCount], 1
1843 jnz ntfsUnsupported ; record fragmented
1844 ; edit directory node
1845 mov edi, [ebp+NTFS.cur_index_buf]
1846 cmp dword [edi], 'INDX'
1848 mov esi, [ebp+NTFS.frs_buffer]
1849 mov ecx, [esi+recordRealSize]
1852 mov esi, [ebp+NTFS.attr_offs]
1853 mov cl, [esi+attributeOffset]
1854 sub esi, [ebp+NTFS.frs_buffer]
1860 mov [edi+fileRealSize], eax
1861 mov dword [edi+fileRealSize+4], 0
1864 mov [edi+fileModified], eax
1865 mov [edi+fileModified+4], edx
1866 mov [edi+recordModified], eax
1867 mov [edi+recordModified+4], edx
1868 mov [edi+fileAccessed], eax
1869 mov [edi+fileAccessed+4], edx
1871 mov eax, [ebp+NTFS.LastRead]
1872 mov [ebp+NTFS.nodeLastRead], eax
1873 mov [ebp+NTFS.cur_attr], 0x80
1874 mov [ebp+NTFS.cur_offs], 0
1875 mov [ebp+NTFS.cur_size], 0
1879 mov edi, [ebp+NTFS.frs_buffer]
1880 cmp word [edi+baseRecordReuse], 0
1881 jnz ntfsUnsupported ; auxiliary record
1882 mov al, [edi+attributeOffset]
1884 mov al, [edi+attributeOffset]
1887 add esi, fileModified
1892 mov ecx, [ebp+NTFS.attr_offs]
1893 cmp word [ecx+attributeFlags], 0
1896 cmp byte [ecx+nonResidentFlag], 0
1898 cmp [ecx+attributeRealSize+4], edx
1900 cmp [ecx+attributeRealSize], eax
1901 jz ntfs_WriteFile.writeNode
1903 jmp ntfs_WriteFile.resizeAttribute
1906 bt dword [eax+fileFlags], 28
1914 cmp [ebp+NTFS.fragmentCount], 1
1915 jnz ntfsUnsupported ; record fragmented
1916 ; 2. Prepare directory record
1920 @@: ; count characters
1923 jz ntfsNotFound ; path folder not found
1928 push ecx ; name length in chars
1933 mov edi, [ebp+NTFS.cur_index_buf]
1935 mov [ebp+NTFS.fileRealSize], eax
1937 mov [ebp+NTFS.fileDataBuffer], eax
1938 push ecx ; index length
1941 cmp dword [edi], 'INDX'
1943 mov esi, [ebp+NTFS.frs_buffer] ; indexRoot
1944 mov ecx, [esi+recordRealSize]
1946 cmp [esi+recordAllocatedSize], edx
1948 mov [esi+recordRealSize], edx
1951 mov edi, [ebp+NTFS.indexRoot]
1952 sub edi, [ebp+NTFS.frs_buffer]
1953 add edi, [ebp+NTFS.cur_index_buf]
1955 add [edi+sizeWithHeader], esi
1956 add [edi+sizeWithoutHeader], esi
1957 mov cl, [edi+attributeOffset]
1959 add [edi+rootNode+nodeRealSize], esi
1960 add [edi+rootNode+nodeAllocatedSize], esi
1961 sub eax, [ebp+NTFS.cur_index_buf]
1963 mov edi, [ebp+NTFS.cur_index_buf]
1966 .growTree: ; create indexRecord
1967 mov edi, [ebp+NTFS.cur_index_buf]
1971 mov esi, [ebp+NTFS.indexRoot]
1972 mov al, [esi+attributeOffset]
1976 mov eax, [esi+indexRecordSize]
1977 cmp eax, [ebp+NTFS.frs_size]
1981 mov edi, [ebp+NTFS.cur_index_buf]
1982 mov dword[edi], 'INDX'
1983 mov byte [edi+updateSequenceOffset], 28h
1984 mov [edi+updateSequenceSize], al
1987 add eax, 28h-recordNode+7
1989 mov [edi+indexOffset], eax
1990 mov ecx, [esi+indexRecordSize]
1992 mov [edi+nodeAllocatedSize], ecx
1995 mov ecx, [esi+nodeRealSize]
1996 sub ecx, [esi+indexOffset]
1998 mov [edi+nodeRealSize], eax
1999 mov eax, [esi+nonLeafFlag]
2000 mov [edi+nonLeafFlag], eax
2002 add esi, [esi+indexOffset]
2003 add edi, [edi+indexOffset]
2004 rep movsd ; copy root indexes
2011 mov byte [edi+indexOffset], 16
2012 mov byte [edi+nodeRealSize], 28h
2013 mov byte [edi+nodeAllocatedSize], 28h
2014 mov byte [edi+nonLeafFlag], 1
2015 mov byte [edi+16+indexAllocatedSize], 18h
2016 mov byte [edi+16+indexFlags], 3
2017 mov esi, [ebp+NTFS.indexRoot]
2021 mov word [esi+sizeWithoutHeader], 38h
2022 xchg [esi+sizeWithHeader], eax
2024 mov [ebp+NTFS.attr_offs], edi
2025 cmp byte [esi], 0xA0
2027 cmp dword [esi+attributeAllocatedSize], 0
2029 mov eax, [ebp+NTFS.frs_buffer]
2031 add ecx, [eax+recordRealSize]
2036 mov [eax+recordRealSize], edi
2039 mov eax, [ebp+NTFS.newRecord]
2040 mov edi, [ebp+NTFS.cur_index_buf]
2041 mov [edi+recordVCN], eax
2042 mov edi, [ebp+NTFS.attr_offs]
2050 mov eax, [ebp+NTFS.cur_subnode_size]
2051 cmp eax, [ebp+NTFS.cur_size]
2053 cmp [ebp+NTFS.sectors_per_cluster], 1
2057 mov [ebp+NTFS.fileDataSize], eax
2058 mov edi, [ebp+NTFS.BitmapStart]
2060 movi eax, ERROR_DISK_FULL
2062 ; create $IndexAllocation
2063 mov edi, [ebp+NTFS.attr_offs]
2064 mov byte [edi+attributeType], 0xA0
2065 mov byte [edi+nonResidentFlag], 1
2066 mov byte [edi+nameLength], 4
2067 mov byte [edi+nameOffset], 40h
2068 mov byte [edi+dataRunsOffset], 48h
2069 mov byte [edi+sizeWithHeader], 50h
2070 mov eax, [ebp+NTFS.fileDataSize]
2072 mov [edi+lastVCN], eax
2074 mul [ebp+NTFS.sectors_per_cluster]
2076 mov [edi+attributeAllocatedSize], eax
2077 mov [edi+attributeRealSize], eax
2078 mov [edi+initialDataSize], eax
2079 mov dword[edi+40h], 490024h ; unicode $I30
2080 mov dword[edi+40h+4], 300033h
2085 mov esi, [ebp+NTFS.frs_buffer]
2087 mov al, [esi+newAttributeID]
2088 mov [edi+attributeID], al
2092 mov [edi+attributeID], al
2094 mov [esi+newAttributeID], al
2095 mov byte [edi+attributeType], 0xB0
2096 mov byte [edi+nameLength], 4
2097 mov byte [edi+nameOffset], 18h
2098 mov byte [edi+attributeOffset], 20h
2099 mov byte [edi+sizeWithoutHeader], 8
2100 mov byte [edi+sizeWithHeader], 28h
2101 mov dword[edi+18h], 490024h ; unicode $I30
2102 mov dword[edi+18h+4], 300033h
2103 mov byte [edi+20h], 1
2104 mov dword[edi+28h], -1
2107 mov [esi+recordRealSize], edi
2108 mov eax, [ebp+NTFS.fileDataStart]
2109 mul [ebp+NTFS.sectors_per_cluster]
2114 mov [ebp+NTFS.cur_size], 0
2115 call ntfs_read_attr.continue
2116 movi eax, ERROR_FS_FAIL
2118 mov edx, [ebp+NTFS.LastRead]
2120 mov ebx, [ebp+NTFS.cur_index_buf]
2122 mov ebx, [ebp+NTFS.frs_buffer]
2123 mov edx, [ebp+NTFS.rootLastRead]
2126 call ntfs_find_lfn.doit2
2129 mov edi, [ebp+NTFS.cur_index_buf]
2133 add edx, [edi+nodeRealSize]
2134 cmp [edi+nodeAllocatedSize], edx
2136 mov [edi+nodeRealSize], edx
2144 ; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
2146 ; [ebp+NTFS.newRecord] = node VCN
2147 ; [ebp+NTFS.cur_offs]
2148 ; CF=1 -> eax = error code
2149 mov esi, [ebp+NTFS.attr_offs]
2150 add esi, [esi+sizeWithHeader]
2151 cmp byte [esi], 0xB0
2153 movzx ecx, word [esi+sizeWithoutHeader]
2155 movzx edi, byte [esi+attributeOffset]
2163 ; extend folder $Bitmap
2164 add word [esi+sizeWithHeader], 8
2165 add word [esi+sizeWithoutHeader], 8
2166 mov esi, [ebp+NTFS.frs_buffer]
2167 mov eax, [esi+recordRealSize]
2169 cmp [esi+recordAllocatedSize], eax
2171 mov [esi+recordRealSize], eax
2187 mul [ebp+NTFS.cur_subnode_size]
2188 mov [ebp+NTFS.newRecord], eax
2189 mov ecx, [ebp+NTFS.cur_size]
2190 cmp ecx, [ebp+NTFS.cur_subnode_size]
2192 mul [ebp+NTFS.sectors_per_cluster]
2194 mov [ebp+NTFS.cur_offs], eax
2197 mov esi, [ebp+NTFS.attr_offs]
2198 cmp [esi+attributeAllocatedSize], eax
2204 movi eax, ERROR_UNSUPPORTED_FS
2209 .arborizeTree: ; find median index
2210 mov ecx, [edi+nodeRealSize]
2211 sub ecx, [edi+indexOffset]
2213 add edi, [edi+indexOffset]
2217 mov ax, [edi+indexAllocatedSize]
2221 mov esi, [ebp+NTFS.secondIndexBuffer]
2222 cmp dword [esi], 'INDX'
2224 ; move index to the root node
2225 mov esi, [ebp+NTFS.frs_buffer]
2228 add ecx, [esi+recordRealSize]
2229 cmp [esi+recordAllocatedSize], ecx
2235 mov edi, [ebp+NTFS.indexRoot]
2236 add [ebp+NTFS.attr_offs], eax
2237 add [edi+sizeWithHeader], eax
2238 add [edi+sizeWithoutHeader], eax
2239 movzx ecx, byte [edi+attributeOffset]
2241 add [ecx+rootNode+nodeRealSize], eax
2242 add [ecx+rootNode+nodeAllocatedSize], eax
2243 add ecx, [ebp+NTFS.indexPointer]
2244 sub ecx, [ebp+NTFS.secondIndexBuffer]
2245 mov esi, [ebp+NTFS.frs_buffer]
2246 add [esi+recordRealSize], eax
2247 add esi, [esi+recordRealSize]
2256 rep movsd ; make space
2261 add word [esi+indexAllocatedSize], 8
2262 mov byte [esi+indexFlags], 1
2267 rep movsd ; insert index
2268 mov eax, [ebp+NTFS.newRecord]
2272 .growBranch: ; move node and replace it with empty one
2273 mov esi, [ebp+NTFS.cur_index_buf]
2274 mov edi, [ebp+NTFS.secondIndexBuffer]
2275 mov eax, [esi+recordVCN]
2276 mov [edi+recordVCN], eax
2278 mov eax, [edi+indexOffset]
2280 mov [edi+nodeRealSize], eax
2281 add edi, [edi+indexOffset]
2284 mov [ebp+NTFS.indexPointer], edi
2288 mov eax, [ebp+NTFS.newRecord]
2289 mov byte [edi+indexAllocatedSize], 18h
2290 mov byte [edi+indexFlags], 3
2292 mov [esi+recordVCN], eax
2293 mov eax, [ebp+NTFS.LastRead]
2294 mov [ebp+NTFS.nodeLastRead], eax
2295 push [ebp+NTFS.cur_size]
2296 mov [ebp+NTFS.cur_size], 0
2297 call ntfs_read_attr.continue
2298 pop [ebp+NTFS.cur_size]
2299 movi eax, ERROR_FS_FAIL
2302 @@: ; move index to the branch node
2307 mov esi, [ebp+NTFS.secondIndexBuffer]
2309 mov ecx, [esi+nodeRealSize]
2311 cmp [esi+nodeAllocatedSize], eax
2313 mov [esi+nodeRealSize], eax
2314 lea edi, [esi+eax-4]
2317 sub ecx, [ebp+NTFS.indexPointer]
2321 rep movsd ; make space
2329 add word [esi+indexAllocatedSize], 8
2330 mov byte [esi+indexFlags], 1
2332 rep movsd ; insert index
2333 mov eax, [ebp+NTFS.newRecord]
2335 mov ebx, [ebp+NTFS.secondIndexBuffer]
2336 mov edx, [ebp+NTFS.nodeLastRead]
2341 mov edi, [ebp+NTFS.cur_index_buf]
2344 add eax, [edi+recordNode+nodeRealSize]
2347 mov ecx, [edi+recordNode+indexOffset]
2353 mov edi, [ebp+NTFS.secondIndexBuffer]
2359 mov edi, [ebp+NTFS.secondIndexBuffer]
2360 mov [edi+recordNode+nodeRealSize], eax
2366 mov byte [esi+indexAllocatedSize], 16
2367 mov byte [esi+indexFlags], 2
2368 mov esi, [ebp+NTFS.cur_index_buf]
2369 mov eax, [ebp+NTFS.newRecord]
2370 mov [esi+recordVCN], eax
2373 mov [esi+nodeRealSize], edi
2374 mov ebx, [ebp+NTFS.secondIndexBuffer]
2375 mov edx, [ebp+NTFS.LastRead]
2385 sub ecx, eax ; eax = pointer in the record
2389 rep movsd ; move forward, make space
2397 mov [edi+fileCreated], eax
2398 mov [edi+fileCreated+4], edx
2399 mov [edi+fileModified], eax
2400 mov [edi+fileModified+4], edx
2401 mov [edi+recordModified], eax
2402 mov [edi+recordModified+4], edx
2403 mov [edi+fileAccessed], eax
2404 mov [edi+fileAccessed+4], edx
2407 mov [edi+indexAllocatedSize], cx ; fill index with data
2411 mov [edi+indexRawSize], ax
2412 mov eax, [ebp+NTFS.cur_iRecord]
2413 mov [edi+directoryRecordReference], eax
2414 mov eax, [ebp+NTFS.frs_buffer]
2415 mov eax, [eax+reuseCounter]
2416 mov [edi+directoryReferenceReuse], ax
2417 mov eax, [ebp+NTFS.frs_size]
2419 add ecx, 30h+48h+8+18h+8
2421 mov eax, [ebp+NTFS.fileRealSize]
2423 mov [edi+fileRealSize], eax
2424 cmp [ebp+NTFS.frs_size], ecx
2428 mov ecx, [ebp+NTFS.sectors_per_cluster]
2434 mov [ebp+NTFS.fileDataSize], eax
2436 mov [edi+fileAllocatedSize], eax
2438 mov [ebp+NTFS.indexPointer], edi
2439 mov [edi+fileNameLength], cl
2441 @@: ; record filename
2445 mov eax, [ebp+NTFS.LastRead]
2446 mov [ebp+NTFS.nodeLastRead], eax
2447 cmp [ebp+NTFS.bFolder], 0
2449 mov edi, [ebp+NTFS.indexPointer]
2450 bts dword [edi+fileFlags], 28
2454 cmp [ebp+NTFS.fileDataSize], 0
2456 mov edi, [ebp+NTFS.BitmapStart]
2459 mov eax, [ebp+NTFS.fileDataStart]
2460 mul [ebp+NTFS.sectors_per_cluster]
2461 mov ecx, [ebp+NTFS.fileRealSize]
2464 mov ebx, [ebp+NTFS.fileDataBuffer]
2469 .mftBitmap: ; search for free record
2470 mov edi, [ebp+NTFS.mftBitmapBuffer]
2471 mov ecx, [ebp+NTFS.mftBitmapSize]
2477 movzx eax, byte [edi]
2480 jz .extendBitmapMFT ; no free records
2482 ; get record location
2483 sub edi, [ebp+NTFS.mftBitmapBuffer]
2486 mov [ebp+NTFS.newRecord], edi
2487 mov eax, [ebp+NTFS.frs_size]
2490 mov [ebp+NTFS.cur_iRecord], 0
2491 mov [ebp+NTFS.cur_attr], 0x80
2492 mov [ebp+NTFS.cur_offs], eax
2494 mov [ebp+NTFS.cur_size], 0
2495 mov eax, [ebp+NTFS.frs_buffer]
2496 mov [ebp+NTFS.cur_buf], eax
2500 cmp eax, [ebp+NTFS.mftSize]
2505 mov eax, [ebp+NTFS.sectors_per_cluster]
2506 mov [ebp+NTFS.cur_offs], eax
2508 cmp [ebp+NTFS.mftBitmapSize], eax
2510 mov [ebp+NTFS.cur_iRecord], 0
2511 mov [ebp+NTFS.cur_attr], 0xB0
2512 mov [ebp+NTFS.cur_size], 0
2515 mov eax, [ebp+NTFS.mft_cluster]
2516 mul [ebp+NTFS.sectors_per_cluster]
2517 cmp eax, [ebp+NTFS.LastRead]
2518 jnz ntfsUnsupported ; auxiliary record
2519 mov edi, [ebp+NTFS.mftBitmapBuffer]
2520 mov ecx, [ebp+NTFS.mftBitmapSize]
2523 mov edx, [ebp+NTFS.attr_offs]
2525 mov [edx+attributeRealSize], ecx
2526 mov [edx+initialDataSize], ecx
2528 mov [ebp+NTFS.newRecord], eax
2530 mov dword [edi+4], 0
2531 mov [ebp+NTFS.cur_attr], 0x80
2532 mov [ebp+NTFS.cur_offs], 0
2533 call ntfs_read_attr.newAttribute
2535 mov [ebp+NTFS.mftBitmapSize], ecx
2537 mov eax, [ebp+NTFS.mft_cluster]
2538 mul [ebp+NTFS.sectors_per_cluster]
2539 cmp eax, [ebp+NTFS.LastRead]
2540 jnz ntfsUnsupported ; auxiliary record
2541 mov ecx, [ebp+NTFS.attr_offs]
2542 mov eax, [ecx+attributeRealSize]
2543 mov edx, [ecx+attributeRealSize+4]
2547 push [ebp+NTFS.fileDataStart]
2548 push [ebp+NTFS.fileDataSize]
2549 call resizeAttribute
2551 mov ebx, [ebp+NTFS.frs_buffer]
2552 mov edx, [ebp+NTFS.LastRead]
2553 call writeRecord ; $MFT
2554 mov eax, [ebp+NTFS.mftmirr_cluster]
2555 mul [ebp+NTFS.sectors_per_cluster]
2556 mov ecx, [ebp+NTFS.frs_size]
2558 call fs_write64_sys ; $MFTMirr
2559 ; update $MFT retrieval information
2560 mov edi, [ebp+NTFS.mft_retrieval_end]
2563 mov edx, [ebp+NTFS.fileDataSize]
2564 cmp eax, [ebp+NTFS.fileDataStart]
2569 lea eax, [ebp+NTFS.attrlist_buf]
2573 mov eax, [ebp+NTFS.fileDataStart]
2575 add [ebp+NTFS.mft_retrieval_end], 8
2577 mov eax, [ebp+NTFS.fileDataSize]
2578 mul [ebp+NTFS.sectors_per_cluster]
2579 add [ebp+NTFS.mftSize], eax
2581 pop [ebp+NTFS.fileDataSize]
2582 pop [ebp+NTFS.fileDataStart]
2584 mov ecx, [ebp+NTFS.frs_size]
2586 mov edi, [ebp+NTFS.frs_buffer]
2589 mov esi, [ebp+NTFS.indexPointer]
2590 mov eax, [ebp+NTFS.newRecord]
2591 mov [esi+fileRecordReference], eax
2593 mov [esi+fileReferenceReuse], ax
2594 mov edi, [ebp+NTFS.frs_buffer]
2596 mov [edi+reuseCounter], ax
2598 mov eax, [ebp+NTFS.frs_size]
2599 mov [edi+recordAllocatedSize], eax
2602 mov [edi+updateSequenceSize], al
2606 mov dword[edi], 'FILE'
2607 mov byte [edi+updateSequenceOffset], 2ah
2608 mov byte [edi+hardLinkCounter], 1
2609 mov byte [edi+newAttributeID], 3
2610 mov [edi+attributeOffset], al
2612 ; $StandardInformation
2613 mov byte [edi+attributeType], 10h
2614 mov byte [edi+sizeWithHeader], 48h
2615 mov byte [edi+sizeWithoutHeader], 30h
2616 mov byte [edi+attributeOffset], 18h
2618 add esi, fileCreated
2622 mov esi, [ebp+NTFS.indexPointer]
2624 mov byte [edi+attributeType], 30h
2625 mov byte [edi+attributeID], 1
2626 mov byte [edi+attributeOffset], 18h
2627 mov byte [edi+indexedFlag], 1
2628 mov cx, [esi+indexRawSize]
2629 mov [edi+sizeWithoutHeader], ecx
2630 mov cx, [esi+indexAllocatedSize]
2632 mov [edi+sizeWithHeader], ecx
2638 mov byte [edi+sizeWithHeader], 50h
2639 mov byte [edi+attributeID], 2
2640 cmp [ebp+NTFS.bFolder], 1
2643 mov byte [edi+attributeType], 80h
2644 mov eax, [ebp+NTFS.fileDataSize]
2647 mov esi, [ebp+NTFS.indexPointer]
2649 mov [edi+lastVCN], eax
2650 mov byte [edi+nonResidentFlag], 1
2651 mov byte [edi+dataRunsOffset], 40h
2652 mov eax, [esi+fileAllocatedSize]
2653 mov [edi+attributeAllocatedSize], eax
2654 mov eax, [esi+fileRealSize]
2655 mov [edi+attributeRealSize], eax
2656 mov [edi+initialDataSize], eax
2665 mov ecx, [ebp+NTFS.fileRealSize]
2666 mov [edi+sizeWithoutHeader], ecx
2667 mov byte [edi+attributeOffset], 18h
2669 mov esi, [ebp+NTFS.fileDataBuffer]
2678 mov [edi+sizeWithHeader], eax
2684 mov byte [edi+attributeType], 90h
2685 mov byte [edi+nameLength], 4
2686 mov byte [edi+nameOffset], 18h
2687 mov byte [edi+sizeWithoutHeader], 30h
2688 mov byte [edi+attributeOffset], 20h
2689 mov dword[edi+18h], 490024h ; unicode $I30
2690 mov dword[edi+18h+4], 300033h
2691 mov byte [edi+20h+indexedAttributesType], 30h
2692 mov byte [edi+20h+collationRule], 1
2693 mov eax, [ebp+NTFS.sectors_per_cluster]
2699 cmp eax, [ebp+NTFS.frs_size]
2702 mov [edi+20h+indexRecordSize], eax
2703 mov [edi+20h+indexRecordSizeClus], dl
2704 mov byte [edi+30h+indexOffset], 16
2705 mov byte [edi+30h+nodeRealSize], 32
2706 mov byte [edi+30h+nodeAllocatedSize], 32
2707 mov byte [edi+40h+indexAllocatedSize], 16
2708 mov byte [edi+40h+indexFlags], 2
2712 mov ebx, [ebp+NTFS.frs_buffer]
2714 mov dword [edi+4], 0
2717 mov [ebx+recordFlags], al
2718 mov [ebx+recordRealSize], edi
2719 mov edx, [ebp+NTFS.LastRead]
2722 mov eax, [ebp+NTFS.newRecord]
2726 add eax, [ebp+NTFS.mftBitmapLocation]
2727 add ebx, [ebp+NTFS.mftBitmapBuffer]
2731 ; 5. Write directory node
2732 mov ebx, [ebp+NTFS.cur_index_buf]
2733 mov edx, [ebp+NTFS.nodeLastRead]
2735 mov ebx, [ebp+NTFS.fileRealSize]
2737 mov esi, [ebp+PARTITION.Disk]
2744 ; make updateSequence and write to disk
2747 ; edx = partition sector
2750 movzx ecx, word [esi+updateSequenceOffset]
2755 mov cx, [esi+updateSequenceSize]
2770 ; [ebp+NTFS.fileDataStart] = position value
2771 ; [ebp+NTFS.fileDataSize] = size value
2772 ; edi -> destination
2773 ; esi -> attribute header
2774 mov eax, [ebp+NTFS.fileDataStart]
2783 mov eax, [ebp+NTFS.fileDataSize]
2790 lea eax, [edi+edx+1]
2793 sub eax, [esi+sizeWithHeader]
2795 add word [esi+sizeWithHeader], 8 ; extend attribute
2796 mov esi, [ebp+NTFS.frs_buffer]
2797 mov eax, [esi+recordRealSize]
2799 cmp [esi+recordAllocatedSize], eax
2800 jc .end ; no space in the record
2801 mov [esi+recordRealSize], eax
2820 lea esi, [ebp+NTFS.fileDataSize]
2822 lea esi, [ebp+NTFS.fileDataStart]
2831 ; [ebp+NTFS.frs_buffer] -> file record
2832 ; [ebp+NTFS.attr_offs] -> attribute
2833 ; edx:eax = new size
2835 ; [ebp+NTFS.fileDataSize] = clusters added (positive)
2836 ; [ebp+NTFS.fileDataStart] = added block
2837 ; CF=1 -> eax = error code
2838 mov esi, [ebp+NTFS.attr_offs]
2839 mov dword [ebp+NTFS.attr_size], eax
2840 mov dword [ebp+NTFS.attr_size+4], edx
2841 cmp byte [esi+nonResidentFlag], 0
2843 mov ecx, [ebp+NTFS.sectors_per_cluster]
2845 mov [esi+attributeRealSize], eax
2846 mov [esi+attributeRealSize+4], edx
2847 mov [esi+initialDataSize], eax
2848 mov [esi+initialDataSize+4], edx
2856 mov [esi+attributeAllocatedSize], eax
2857 mov [esi+attributeAllocatedSize+4], edx
2858 mov ecx, [esi+lastVCN]
2859 mov [esi+lastVCN], edi
2860 movzx eax, byte [esi+dataRunsOffset]
2862 mov [ebp+NTFS.fileDataSize], edi
2868 push edi edi edi edi
2873 call ntfs_decode_mcb_entry
2882 cmp edi, [ebp+NTFS.BitmapStart]
2884 cmp [ebp+NTFS.cur_iRecord], 0
2886 mov edi, [ebp+NTFS.BitmapStart]
2890 mov eax, [ebp+NTFS.fileDataStart]
2897 pop [ebp+NTFS.fileDataStart]
2899 push [ebp+NTFS.fileDataSize]
2900 add [ebp+NTFS.fileDataSize], edx
2907 push [ebp+NTFS.fileDataSize]
2909 mov [ebp+NTFS.fileDataStart], eax
2911 mov esi, [ebp+NTFS.attr_offs]
2913 pop [ebp+NTFS.fileDataSize]
2914 pop [ebp+NTFS.fileDataStart]
2915 movi eax, ERROR_UNSUPPORTED_FS
2923 movi eax, ERROR_DISK_FULL
2927 movi eax, ERROR_FS_FAIL
2940 call ntfs_decode_mcb_entry
2948 mov [ebp+NTFS.fileDataSize], ecx
2949 mov [ebp+NTFS.fileDataStart], eax
2957 call ntfs_decode_mcb_entry
2968 cmp [ebp+NTFS.fileDataSize], 0
2970 mov esi, [ebp+NTFS.attr_offs]
2972 mov [ebp+NTFS.fileDataSize], 0
2981 add ax, [esi+attributeOffset]
2982 sub eax, [esi+sizeWithHeader]
2984 mov edi, [ebp+NTFS.frs_buffer]
2986 add ecx, [edi+recordRealSize]
2987 cmp [edi+recordAllocatedSize], ecx
2991 add [edi+recordRealSize], eax
2992 add edi, [edi+recordRealSize]
2993 add [esi+sizeWithHeader], eax
2994 add esi, [esi+sizeWithHeader]
3008 mov esi, [ebp+NTFS.attr_offs]
3010 mov eax, dword [ebp+NTFS.attr_size]
3011 mov [esi+sizeWithoutHeader], eax
3012 mov [ebp+NTFS.fileDataSize], 0
3016 .nonResident: ; convert resident to non-resident
3017 mov eax, dword [ebp+NTFS.attr_size]
3020 mov ecx, [ebp+NTFS.sectors_per_cluster]
3024 mov [ebp+NTFS.fileDataSize], eax
3025 mov edi, [ebp+NTFS.BitmapStart]
3030 mov esi, [ebp+NTFS.attr_offs]
3036 cmp eax, [esi+sizeWithoutHeader]
3040 stdcall kernel_alloc, eax
3047 mov al, [esi+attributeOffset]
3048 mov ecx, [esi+sizeWithoutHeader]
3052 mov eax, [ebp+NTFS.fileDataStart]
3053 mul [ebp+NTFS.sectors_per_cluster]
3057 stdcall kernel_free, ebx
3058 mov esi, [ebp+NTFS.attr_offs]
3059 add esi, [esi+sizeWithHeader]
3060 mov ecx, [ebp+NTFS.frs_buffer]
3061 add ecx, [ecx+recordRealSize]
3064 lea edi, [ebp+NTFS.bitmap_buf]
3067 mov edi, [ebp+NTFS.attr_offs]
3072 mov edi, [ebp+NTFS.attr_offs]
3073 mov eax, [ebp+NTFS.fileDataSize]
3075 mov [edi+lastVCN], eax
3077 mov ecx, [ebp+NTFS.sectors_per_cluster]
3080 mov byte [edi+sizeWithHeader], 50h
3081 mov byte [edi+nonResidentFlag], 1
3082 mov byte [edi+dataRunsOffset], 40h
3083 mov [edi+attributeAllocatedSize], eax
3084 mov [edi+attributeAllocatedSize+4], edx
3085 mov eax, dword [ebp+NTFS.attr_size]
3086 mov edx, dword [ebp+NTFS.attr_size+4]
3087 mov [edi+attributeRealSize], eax
3088 mov [edi+attributeRealSize+4], edx
3089 mov [edi+initialDataSize], eax
3090 mov [edi+initialDataSize+4], edx
3095 mov edi, [ebp+NTFS.attr_offs]
3099 mov [edi+sizeWithHeader], eax
3101 lea esi, [ebp+NTFS.bitmap_buf]
3104 mov esi, [ebp+NTFS.frs_buffer]
3106 mov [esi+recordRealSize], edi
3108 sub [ebp+NTFS.fileDataSize], edx
3109 add [ebp+NTFS.fileDataStart], edx
3112 .makeResident: ; convert non-resident to empty resident
3113 movzx eax, byte [esi+dataRunsOffset]
3114 mov byte [esi+nonResidentFlag], 0
3115 mov dword [esi+sizeWithoutHeader], 0
3116 mov dword [esi+attributeOffset], 18h
3121 call ntfs_decode_mcb_entry
3131 mov [ebp+NTFS.fileDataSize], 0
3135 ; clean up to 16 Mb of disk space
3137 ; [ebp+NTFS.fileDataStart] = block to clean
3138 ; [ebp+NTFS.fileDataSize] = block size
3139 mov eax, [ebp+NTFS.fileDataSize]
3142 mul [ebp+NTFS.sectors_per_cluster]
3147 stdcall kernel_alloc, eax
3157 mov eax, [ebp+NTFS.fileDataStart]
3158 mul [ebp+NTFS.sectors_per_cluster]
3159 mov [ebp+NTFS.LastRead], eax
3162 stdcall kernel_free, ebx
3167 ; allocate disk space
3169 ; edi = offset in bitmap to start search from
3170 ; [ebp+NTFS.fileDataSize] = block size in clusters
3172 ; [ebp+NTFS.fileDataStart] = allocated block starting cluster
3174 mov ecx, [ebp+NTFS.BitmapBuffer]
3176 add ecx, [ebp+NTFS.BitmapSize]
3180 call bitmapBuffering
3186 mov eax, [ebp+NTFS.fileDataSize]
3189 mov ebx, eax ; bitmap dwords
3191 mov ecx, [ebp+NTFS.BitmapBuffer]
3192 add ecx, [ebp+NTFS.BitmapSize]
3197 repnz scasd ; search for empty dword
3199 call bitmapBuffering
3204 call bitmapBuffering
3211 repz scasd ; check following dwords
3218 push edx ; starting bit
3219 push esi ; starting dword
3223 mov eax, [ebp+NTFS.fileDataSize]
3230 bsf ecx, eax ; check last dword
3240 call bitmapBuffering
3242 .small: ; less than 32 clusters
3251 bsf ecx, eax ; first 0
3256 bsf edx, eax ; next 1
3259 cmp edx, [ebp+NTFS.fileDataSize]
3260 jnc .got ; fits inside
3273 cmp edx, [ebp+NTFS.fileDataSize]
3277 push ecx ; starting bit
3278 push edi ; starting dword
3292 sub ecx, [ebp+NTFS.fileDataSize]
3294 shl eax, cl ; fits inside dword
3316 sub eax, [ebp+NTFS.BitmapBuffer]
3320 mov ecx, [ebp+NTFS.fileDataSize]
3321 mov [ebp+NTFS.fileDataStart], eax
3329 add eax, [ebp+NTFS.BitmapLocation]
3330 add ebx, [ebp+NTFS.BitmapBuffer]
3337 ; edi = starting cluster
3338 ; ebx = size in clusters
3342 cmp eax, [ebp+NTFS.BitmapSize]
3344 add eax, [ebp+NTFS.BitmapBuffer]
3347 call bitmapBuffering
3354 add edi, [ebp+NTFS.BitmapBuffer]
3364 shl eax, cl ; fits inside dword
3388 lea ecx, [eax+ebx+4095]
3394 add eax, [ebp+NTFS.BitmapLocation]
3395 add ebx, [ebp+NTFS.BitmapBuffer]
3400 ; Extend BitmapBuffer and read next 32kb of bitmap
3401 ; Warning: $Bitmap fragmentation is not foreseen
3402 ; in: edi -> position in bitmap buffer
3403 ; out: ecx = number of buffered dwords left
3405 mov eax, [ebp+NTFS.BitmapTotalSize]
3406 cmp eax, [ebp+NTFS.BitmapSize]
3408 stdcall alloc_pages, 8
3412 mov ebx, [ebp+NTFS.BitmapBuffer]
3413 add ebx, [ebp+NTFS.BitmapSize]
3417 mov eax, [ebp+NTFS.BitmapSize]
3419 add eax, [ebp+NTFS.BitmapLocation]
3426 mov eax, [ebp+NTFS.BitmapSize]
3428 cmp [ebp+NTFS.BitmapTotalSize], eax
3430 mov eax, [ebp+NTFS.BitmapTotalSize]
3432 mov [ebp+NTFS.BitmapSize], eax
3434 mov ecx, [ebp+NTFS.BitmapBuffer]
3442 mov eax, [ebp+NTFS.BitmapBuffer]
3443 add eax, [ebp+NTFS.BitmapSize]
3451 ;----------------------------------------------------------------
3456 cmp [ebp+NTFS.cur_iRecord], 16
3458 test dword [eax+fileFlags], 10000001h
3460 cmp [ebp+NTFS.fragmentCount], 1
3461 jnz ntfsUnsupported ; record fragmented
3462 ; edit directory node
3463 mov edi, [ebp+NTFS.cur_index_buf]
3464 cmp dword [edi], 'INDX'
3466 mov esi, [ebp+NTFS.frs_buffer]
3467 mov ecx, [esi+recordRealSize]
3470 mov esi, [ebp+NTFS.attr_offs]
3471 mov cl, [esi+attributeOffset]
3472 sub esi, [ebp+NTFS.frs_buffer]
3482 cmp edx, [edi+fileRealSize+4]
3485 cmp [edi+fileRealSize], eax
3488 mov [edi+fileRealSize], eax
3489 mov [edi+fileRealSize+4], edx
3493 mov [edi+fileModified], eax
3494 mov [edi+fileModified+4], edx
3495 mov [edi+recordModified], eax
3496 mov [edi+recordModified+4], edx
3497 mov [edi+fileAccessed], eax
3498 mov [edi+fileAccessed+4], edx
3500 mov eax, [ebp+NTFS.LastRead]
3501 mov [ebp+NTFS.nodeLastRead], eax
3502 mov [ebp+NTFS.cur_attr], 0x80
3503 mov [ebp+NTFS.cur_offs], 0
3504 mov [ebp+NTFS.cur_size], 0
3508 mov edi, [ebp+NTFS.frs_buffer]
3509 cmp word [edi+baseRecordReuse], 0
3510 jnz ntfsUnsupported ; auxiliary record
3511 mov al, [edi+attributeOffset]
3513 mov al, [edi+attributeOffset]
3517 add esi, fileModified
3520 mov ecx, [ebp+NTFS.attr_offs]
3521 cmp word [ecx+attributeFlags], 0
3524 cmp byte [ecx+nonResidentFlag], 0
3526 cmp edx, [ecx+attributeRealSize+4]
3528 jnz .resizeAttribute
3529 cmp [ecx+attributeRealSize], eax
3532 call resizeAttribute
3534 mov ecx, [ebp+NTFS.attr_offs]
3535 cmp byte [ecx+nonResidentFlag], 1
3538 movzx edi, byte [ecx+attributeOffset]
3545 mov ebx, [ebp+NTFS.frs_buffer]
3546 mov edx, [ebp+NTFS.mftLastRead]
3547 call writeRecord ; file
3548 call ntfs_restore_usa_frs
3550 mov ebx, [ebp+NTFS.cur_index_buf]
3551 mov edx, [ebp+NTFS.nodeLastRead]
3552 call writeRecord ; directory
3554 mov ecx, [ebp+NTFS.attr_offs]
3555 cmp byte [ecx+nonResidentFlag], 0
3564 test dword[ebx+4], 1FFh
3566 mov [ebp+NTFS.cur_offs], eax
3567 mov [ebp+NTFS.cur_size], 1
3568 lea edi, [ebp+NTFS.bitmap_buf]
3569 mov [ebp+NTFS.cur_buf], edi
3570 call ntfs_read_attr.continue
3575 sub eax, [ebp+NTFS.cur_read]
3585 mov eax, [ebp+NTFS.LastRead]
3586 lea ebx, [ebp+NTFS.bitmap_buf]
3601 mov [ebp+NTFS.cur_offs], eax
3602 mov [ebp+NTFS.cur_size], ecx
3603 mov [ebp+NTFS.cur_buf], esi
3606 mov [ebp+NTFS.bWriteAttr], 1
3607 call ntfs_read_attr.continue
3608 mov [ebp+NTFS.bWriteAttr], 0
3609 pop [ebp+NTFS.cur_offs]
3614 add esi, [ebp+NTFS.cur_read]
3615 mov [ebp+NTFS.cur_size], 1
3616 lea edi, [ebp+NTFS.bitmap_buf]
3617 mov [ebp+NTFS.cur_buf], edi
3618 call ntfs_read_attr.continue
3622 mov eax, [ebp+NTFS.LastRead]
3623 lea ebx, [ebp+NTFS.bitmap_buf]
3632 ;----------------------------------------------------------------
3637 cmp [ebp+NTFS.cur_iRecord], 16
3639 test byte [eax+fileFlags], 1
3641 cmp [ebp+NTFS.fragmentCount], 1
3642 jnz ntfsUnsupported ; record fragmented
3643 mov ebx, [eax+directoryRecordReference]
3644 mov [ebp+NTFS.newRecord], ebx
3645 mov bx, [eax+fileReferenceReuse]
3646 mov [ebp+NTFS.indexPointer], esi
3647 mov eax, [ebp+NTFS.cur_iRecord]
3649 cmp eax, [ebp+NTFS.mftBitmapSize]
3651 ; examine file record
3652 mov [ebp+NTFS.cur_attr], 0x80 ; file?
3653 mov [ebp+NTFS.cur_offs], 0
3654 mov [ebp+NTFS.cur_size], 0
3658 push ebx eax eax eax eax
3662 mov [ebp+NTFS.cur_attr], 0x90 ; folder?
3663 call ntfs_ReadFolder.doit
3670 jnz ntfsDenied ; folder is not empty
3671 mov [ebp+NTFS.cur_attr], 0xA0
3672 mov [ebp+NTFS.cur_offs], 0
3673 mov [ebp+NTFS.cur_size], 0
3674 call ntfs_read_attr.newAttribute
3675 jc .deleteFileRecord
3677 mov esi, [ebp+NTFS.frs_buffer]
3678 cmp word [esi+baseRecordReuse], 0
3679 jnz ntfsUnsupported ; auxiliary record
3680 cmp word [esi+reuseCounter], bx
3681 jnz .backToIndex ; broken index
3682 test byte [esi+recordFlags], 1
3683 jz .writeBitmapMFT ; record deleted
3684 cmp byte [esi+hardLinkCounter], 3
3686 mov esi, [ebp+NTFS.attr_offs]
3687 cmp byte [esi+nonResidentFlag], 0
3688 jz .deleteFileRecord
3689 movzx eax, byte [esi+dataRunsOffset]
3694 call ntfs_decode_mcb_entry
3705 mov ebx, [ebp+NTFS.frs_buffer]
3706 mov byte [ebx+recordFlags], 0
3707 mov edx, [ebp+NTFS.mftLastRead]
3710 mov eax, [ebp+NTFS.cur_iRecord]
3714 mov edi, [ebp+NTFS.mftBitmapBuffer]
3719 add eax, [ebp+NTFS.mftBitmapLocation]
3725 mov eax, [ebp+NTFS.newRecord]
3726 mov [ebp+NTFS.cur_iRecord], eax
3727 mov esi, [ebp+NTFS.indexPointer]
3728 call ntfs_find_lfn.doit2
3730 mov ebx, [ebp+NTFS.secondIndexBuffer]
3732 mov ebx, [ebp+NTFS.LastRead]
3733 mov [ebp+NTFS.nodeLastRead], ebx
3735 test byte [eax+indexFlags], 1
3736 jz .deleteIndex ; no subnode
3740 movzx edx, word [edi+indexAllocatedSize]
3751 movzx edx, word [eax+indexAllocatedSize]
3752 mov ecx, [eax+fileRecordReference]
3753 cmp [eax+edx+fileRecordReference], ecx
3755 add dx, [eax+edx+indexAllocatedSize]
3757 mov edi, [ebp+NTFS.cur_index_buf]
3758 cmp dword [edi], 'INDX'
3761 mov edi, [ebp+NTFS.indexRoot]
3762 sub [edi+sizeWithHeader], edx
3763 sub [edi+sizeWithoutHeader], edx
3764 movzx ecx, byte [edi+attributeOffset]
3767 sub [edi+rootNode+nodeRealSize], edx
3768 sub [edi+rootNode+nodeAllocatedSize], edx
3769 mov edi, [ebp+NTFS.frs_buffer]
3770 sub [edi+recordRealSize], edx
3771 mov ecx, [edi+recordRealSize]
3772 cmp [edi+recordAllocatedSize], ecx
3777 sub [edi+nodeRealSize], edx
3778 mov ecx, [edi+nodeRealSize]
3779 cmp [edi+nodeAllocatedSize], ecx
3803 ; copy index from the subnode to replace deleted pointing index
3804 movzx ecx, word [ebx+indexAllocatedSize]
3806 test byte [ebx+indexFlags], 1
3809 movzx edi, word [ebx+edx+indexAllocatedSize]
3812 mov [ebx+edi-8], esi
3813 mov [ebx+indexAllocatedSize], cx
3819 add word [eax+indexAllocatedSize], 8
3820 mov byte [eax+indexFlags], 1
3821 mov edi, [ebp+NTFS.secondIndexBuffer]
3827 mov ebx, [ebp+NTFS.frs_buffer]
3828 mov edx, [ebp+NTFS.rootLastRead]
3830 mov ebx, [ebp+NTFS.cur_index_buf]
3831 cmp dword [ebx], 'INDX'
3833 mov edx, [ebp+NTFS.nodeLastRead]
3836 mov ebx, [ebp+NTFS.secondIndexBuffer]
3839 mov edx, [ebp+NTFS.LastRead]
3847 ; esi=0 -> subnode deleted
3848 ; esi -> replacement index
3849 ; eax = index effective size
3850 movzx edx, word [eax+indexAllocatedSize]
3851 mov eax, [eax+edx-8]
3852 mov edx, [ebp+NTFS.cur_size]
3854 cmp edx, [ebp+NTFS.cur_subnode_size]
3856 mul [ebp+NTFS.sectors_per_cluster]
3858 mov [ebp+NTFS.cur_attr], 0xA0
3859 mov [ebp+NTFS.cur_offs], eax
3861 mov ebx, [ebp+NTFS.secondIndexBuffer]
3863 mov [ebp+NTFS.cur_buf], ebx
3864 call ntfs_read_attr.newAttribute
3865 pop [ebp+NTFS.cur_offs]
3868 cmp dword [esi], 'INDX'
3871 mov [ebp+NTFS.cur_size], eax
3873 call ntfs_restore_usa
3876 add esi, [esi+indexOffset]
3877 test byte [esi+indexFlags], 2
3879 cmp [ebp+NTFS.fragmentCount], 1
3881 jnz .ret ; record fragmented
3885 mov ax, [esi+indexAllocatedSize]
3886 test byte [esi+eax+indexFlags], 2
3888 test byte [esi+indexFlags], 1
3892 push [ebp+NTFS.cur_offs]
3894 pop [ebp+NTFS.cur_offs]
3900 mov ebx, [ebp+NTFS.secondIndexBuffer]
3901 mov [ebp+NTFS.cur_buf], ebx
3902 push [ebp+NTFS.cur_size]
3903 call ntfs_read_attr.continue
3907 call ntfs_restore_usa
3909 movzx eax, word [esi+indexAllocatedSize]
3915 test byte [esi+indexFlags], 1
3918 push [ebp+NTFS.cur_offs]
3920 pop [ebp+NTFS.cur_offs]
3925 mov esi, [ebp+NTFS.attr_offs]
3926 add esi, [esi+sizeWithHeader]
3927 cmp byte [esi], 0xB0
3930 movzx eax, byte [esi+attributeOffset]
3932 mov eax, [ebp+NTFS.cur_offs]
3934 div [ebp+NTFS.cur_size]
3939 mov esi, [ebp+NTFS.secondIndexBuffer]
3944 ;----------------------------------------------------------------
3949 cmp [ebp+NTFS.cur_iRecord], 16
3951 test dword [eax+fileFlags], 10000001h
3953 cmp [ebp+NTFS.fragmentCount], 1
3954 jnz ntfsUnsupported ; record fragmented
3955 ; edit directory node
3956 mov edi, [ebp+NTFS.cur_index_buf]
3957 cmp dword [edi], 'INDX'
3959 mov esi, [ebp+NTFS.frs_buffer]
3960 mov ecx, [esi+recordRealSize]
3963 mov esi, [ebp+NTFS.attr_offs]
3964 mov cl, [esi+attributeOffset]
3965 sub esi, [ebp+NTFS.frs_buffer]
3972 mov [edi+fileRealSize], eax
3973 mov [edi+fileRealSize+4], edx
3976 mov [edi+fileModified], eax
3977 mov [edi+fileModified+4], edx
3978 mov [edi+recordModified], eax
3979 mov [edi+recordModified+4], edx
3980 mov [edi+fileAccessed], eax
3981 mov [edi+fileAccessed+4], edx
3983 mov eax, [ebp+NTFS.LastRead]
3984 mov [ebp+NTFS.nodeLastRead], eax
3985 mov [ebp+NTFS.cur_attr], 0x80
3986 mov [ebp+NTFS.cur_offs], 0
3987 mov [ebp+NTFS.cur_size], 0
3991 mov edi, [ebp+NTFS.frs_buffer]
3992 cmp word [edi+baseRecordReuse], 0
3993 jnz ntfsUnsupported ; auxiliary record
3994 mov al, [edi+attributeOffset]
3996 mov al, [edi+attributeOffset]
4000 add esi, fileModified
4003 mov ecx, [ebp+NTFS.attr_offs]
4004 cmp word [ecx+attributeFlags], 0
4006 cmp byte [ecx+nonResidentFlag], 0
4008 cmp [ecx+attributeRealSize+4], edx
4009 jnz .resizeAttribute
4010 cmp [ecx+attributeRealSize], eax
4011 jnc .resizeAttribute
4012 mov eax, [ecx+attributeRealSize]
4013 mov ecx, [ebp+NTFS.sectors_per_cluster]
4014 mov [ebp+NTFS.cur_size], ecx
4021 mul [ebp+NTFS.sectors_per_cluster]
4022 mov [ebp+NTFS.cur_offs], eax
4023 stdcall kernel_alloc, ecx
4029 mov [ebp+NTFS.cur_buf], eax
4030 call ntfs_read_attr.continue
4035 mov eax, [ebp+NTFS.LastRead]
4037 mov ecx, [ebp+NTFS.sectors_per_cluster]
4042 stdcall kernel_free, esi
4047 call resizeAttribute
4049 mov ebx, [ebp+NTFS.frs_buffer]
4050 mov edx, [ebp+NTFS.mftLastRead]
4051 call writeRecord ; file
4052 mov ebx, [ebp+NTFS.cur_index_buf]
4053 mov edx, [ebp+NTFS.nodeLastRead]
4054 call writeRecord ; directory
4063 ; in: esi -> data block
4064 ; out: edx:eax = seconds since 01.01.1601 x10000000
4065 call fsCalculateTime
4073 ;----------------------------------------------------------------
4083 cmp [ebp+NTFS.fragmentCount], 1
4084 jnz ntfsUnsupported ; record fragmented
4085 mov esi, [ebp+NTFS.cur_index_buf]
4086 cmp dword [esi], 'INDX'
4089 mov esi, [ebp+NTFS.indexRoot]
4090 movzx edx, byte [esi+attributeOffset]
4098 and byte [edi+fileFlags], -28h
4099 or [edi+fileFlags], al
4101 call ntfsCalculateTime
4102 mov [edi+fileCreated], eax
4103 mov [edi+fileCreated+4], edx
4105 call ntfsCalculateTime
4106 mov [edi+fileAccessed], eax
4107 mov [edi+fileAccessed+4], edx
4109 call ntfsCalculateTime
4110 mov [edi+fileModified], eax
4111 mov [edi+fileModified+4], edx
4112 mov ebx, [ebp+NTFS.cur_index_buf]
4113 cmp dword [ebx], 'INDX'
4115 mov ebx, [ebp+NTFS.frs_buffer]
4117 mov edx, [ebp+NTFS.LastRead]
4122 push ERROR_UNSUPPORTED_FS
4128 push ERROR_FILE_NOT_FOUND
4131 push ERROR_ACCESS_DENIED
4137 push ERROR_DISK_FULL