Krn: Fixed the number of functions in the file system drivers
[kolibrios.git] / kernel / trunk / fs / ntfs.inc
blob197c3a169f97091fabb3f37fc3eca0c5292b7cd7
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;;                                                              ;;
3 ;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
4 ;;  Distributed under terms of the GNU General Public License.  ;;
5 ;;                                                              ;;
6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 $Revision$
10 ; NTFS external functions
11 ;   in:
12 ; ebx -> parameter structure of sysfunc 70
13 ; ebp -> NTFS structure
14 ; esi -> path string in UTF-8
15 ;   out:
16 ; eax, ebx = return values for sysfunc 70
17 iglobal
18 align 4
19 ntfs_user_functions:
20         dd      ntfs_free
21         dd      (ntfs_user_functions_end - ntfs_user_functions - 8) / 4
22         dd      ntfs_ReadFile
23         dd      ntfs_ReadFolder
24         dd      ntfs_CreateFile
25         dd      ntfs_WriteFile
26         dd      ntfs_SetFileEnd
27         dd      ntfs_GetFileInfo
28         dd      ntfs_SetFileInfo
29         dd      0
30         dd      ntfs_Delete
31         dd      ntfs_CreateFolder
32 ntfs_user_functions_end:
33 endg
35 ; Basic concepts:
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.
53 ; Offsets:
54     ; record header
55 magic = 0
56 updateSequenceOffset = 4
57 updateSequenceSize = 6
58     ; FileRecord header
59 reuseCounter = 16
60 hardLinkCounter = 12h
61 attributeOffset = 14h
62 recordFlags = 16h
63 recordRealSize = 18h
64 recordAllocatedSize = 1ch
65 baseRecordReference = 20h       ; for auxiliary records
66 baseRecordReuse = 26h
67 newAttributeID = 28h
68     ; attribute header
69 attributeType = 0
70 sizeWithHeader = 4
71 nonResidentFlag = 8
72 nameLength = 9
73 nameOffset = 10
74 attributeFlags = 12
75 attributeID = 14
76     ; resident attribute header
77 sizeWithoutHeader = 10h
78 attributeOffset = 14h
79 indexedFlag = 16h
80     ; non resident attribute header
81 firstVCN = 10h
82 lastVCN = 18h
83 dataRunsOffset = 20h
84 attributeAllocatedSize = 28h
85 attributeRealSize = 30h
86 initialDataSize = 38h
87     ; $IndexRoot
88 indexedAttributesType = 0
89 collationRule = 4
90 indexRecordSize = 8
91 indexRecordSizeClus = 12        ; in sectors if less than one cluster
92 rootNode = 16
93     ; IndexRecord header
94 recordVCN = 16
95 recordNode = 18h
96     ; node header
97 indexOffset = 0
98 nodeRealSize = 4
99 nodeAllocatedSize = 8
100 nonLeafFlag = 12
101     ; $Filename index
102 fileRecordReference = 0
103 fileReferenceReuse = 6
104 indexAllocatedSize = 8
105 indexRawSize = 10
106 indexFlags = 12
107 directoryRecordReference = 16
108 directoryReferenceReuse = 16h
109 fileCreated = 18h
110 fileModified = 20h
111 recordModified = 28h
112 fileAccessed = 30h
113 fileAllocatedSize = 38h
114 fileRealSize = 40h
115 fileFlags = 48h
116 fileNameLength = 50h
117 namespace = 51h
118 fileName = 52h
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  ?
133 BitmapBuffer        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
142 attr_size           dq  ?
143 attr_offs           dd  ?
144 attr_list           dd  ?
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
150 cur_buf             dd  ?
151 cur_read            dd  ?   ; bytes readen
152 cur_tail            dd  ?
153 cur_subnode_size    dd  ?
154 LastRead            dd  ?   ; last readen block of sectors
155 mftLastRead         dd  ?
156 rootLastRead        dd  ?
157 nodeLastRead        dd  ?
158 indexRoot           dd  ?
159 indexPointer        dd  ?
160 newRecord           dd  ?
161 fileDataStart       dd  ?   ; starting cluster
162 fileDataSize        dd  ?   ; in clusters
163 fileDataBuffer      dd  ?
164 fileRealSize        dd  ?   ; in bytes
165 fragmentCount       db  ?
166 bCanContinue        db  ?
167 bFolder             db  ?
168 bWriteAttr          db  ?   ; Warning: Don't forget to turn off!!!
170 mft_retrieval       rb  512
171 align0  rb  1024-NTFS.align0
172 attrlist_buf        rb  1024
173 attrlist_mft_buf    rb  1024
174 bitmap_buf          rb  1024
175 ends
177 ntfs_test_bootsec:
178 ; in: ebx -> buffer, edx = size of partition
179 ; out: CF=1 -> invalid
180 ; 1. Name=='NTFS    '
181         cmp     dword [ebx+3], 'NTFS'
182         jnz     .no
183         cmp     dword [ebx+7], '    '
184         jnz     .no
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
188         jnz     .no
189 ; 3. Number of sectors per cluster must be power of 2
190         movzx   eax, byte [ebx+13]
191         dec     eax
192         js      .no
193         test    al, [ebx+13]
194         jnz     .no
195 ; 4. FAT parameters must be zero
196         cmp     word [ebx+14], 0
197         jnz     .no
198         cmp     dword [ebx+16], 0
199         jnz     .no
200         cmp     byte [ebx+20], 0
201         jnz     .no
202         cmp     word [ebx+22], 0
203         jnz     .no
204         cmp     dword [ebx+32], 0
205         jnz     .no
206 ; 5. Number of sectors <= partition size
207         cmp     dword [ebx+0x2C], 0
208         ja      .no
209         cmp     [ebx+0x28], edx
210         ja      .no
211 ; 6. $MFT and $MFTMirr clusters must be within partition
212         cmp     dword [ebx+0x34], 0
213         ja      .no
214         push    edx
215         movzx   eax, byte [ebx+13]
216         mul     dword [ebx+0x30]
217         test    edx, edx
218         pop     edx
219         jnz     .no
220         cmp     eax, edx
221         ja      .no
222         cmp     dword [ebx+0x3C], 0
223         ja      .no
224         push    edx
225         movzx   eax, byte [ebx+13]
226         mul     dword [ebx+0x38]
227         test    edx, edx
228         pop     edx
229         jnz     .no
230         cmp     eax, edx
231         ja      .no
232 ; 7. Clusters per FRS must be either power of 2 or between -31 and -9
233         movsx   eax, byte [ebx+0x40]
234         cmp     al, -31
235         jl      .no
236         cmp     al, -9
237         jle     @f
238         dec     eax
239         js      .no
240         test    [ebx+0x40], al
241         jnz     .no
242 @@:         ; 8. Same for clusters per IndexAllocationBuffer
243         movsx   eax, byte [ebx+0x44]
244         cmp     al, -31
245         jl      .no
246         cmp     al, -9
247         jle     @f
248         dec     eax
249         js      .no
250         test    [ebx+0x44], al
251         jnz     .no
252 @@:         ; OK, this is correct NTFS bootsector
253         clc
254         ret
255 .no:        ; No, this bootsector isn't NTFS
256         stc
257         ret
259 ; Mount if it's a valid NTFS partition.
260 ntfs_create_partition:
261 ;   in:
262 ; ebp -> PARTITION structure
263 ; ebx -> boot sector
264 ; ebx+512 -> buffer
265 ;   out:
266 ; eax -> NTFS structure, 0 = not NTFS
267         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
268         jnz     .nope
269         mov     edx, dword [ebp+PARTITION.Length]
270         cmp     dword [esp+4], 0
271         jz      .boot_read_ok
272         add     ebx, 512
273         lea     eax, [edx-1]
274         call    fs_read32_sys
275         test    eax, eax
276         jnz     @f
277         call    ntfs_test_bootsec
278         jnc     .ntfs_setup
280         mov     eax, edx
281         shr     eax, 1
282         call    fs_read32_sys
283         test    eax, eax
284         jnz     .nope
285 .boot_read_ok:
286         call    ntfs_test_bootsec
287         jnc     .ntfs_setup
288 .nope:
289         xor     eax, eax
290         jmp     .exit
292 .ntfs_setup:    ; By given bootsector, initialize some NTFS variables
293         stdcall kernel_alloc, 1000h
294         test    eax, eax
295         jz      .exit
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
305         push    ebx ebp esi
306         mov     ebp, eax
307         lea     ecx, [ebp+NTFS.Lock]
308         call    mutex_init
309         movzx   eax, byte [ebx+13]
310         mov     [ebp+NTFS.sectors_per_cluster], eax
311         mov     eax, [ebx+0x28]
312         mov     dword [ebp+NTFS.Length], eax
313         and     dword [ebp+NTFS.Length+4], 0
314         mov     eax, [ebx+0x30]
315         mov     [ebp+NTFS.mft_cluster], eax
316         mov     eax, [ebx+0x38]
317         mov     [ebp+NTFS.mftmirr_cluster], eax
318         movsx   eax, byte [ebx+0x40]
319         test    eax, eax
320         js      @f
321         mul     [ebp+NTFS.sectors_per_cluster]
322         shl     eax, 9
323         jmp     .1
326         neg     eax
327         mov     ecx, eax
328         mov     eax, 1
329         shl     eax, cl
331         mov     [ebp+NTFS.frs_size], eax
332         stdcall kernel_alloc, eax
333         test    eax, eax
334         jz      .fail_free
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]
340         shr     ecx, 9
341         mov     ebx, [ebp+NTFS.frs_buffer]
342         call    fs_read64_sys
343         test    eax, eax
344         jnz     .usemirr
345         cmp     dword [ebx], 'FILE'
346         jnz     .usemirr
347         call    ntfs_restore_usa_frs
348         jnc     .mftok
349 .usemirr:
350         mov     eax, [ebp+NTFS.mftmirr_cluster]
351         mul     [ebp+NTFS.sectors_per_cluster]
352         mov     ecx, [ebp+NTFS.frs_size]
353         shr     ecx, 9
354         mov     ebx, [ebp+NTFS.frs_buffer]
355         call    fs_read64_sys
356         test    eax, eax
357         jnz     .fail_free_frs
358         cmp     dword [ebx], 'FILE'
359         jnz     .fail_free_frs
360         call    ntfs_restore_usa_frs
361         jc      .fail_free_frs
362 .mftok:     ; prepare $MFT retrieval information
363 ; search for unnamed non-resident $DATA attribute
364         movzx   eax, word [ebx+attributeOffset]
365         add     eax, ebx
366 .scandata:
367         cmp     dword [eax], -1
368         jz      .fail_free_frs
369         cmp     dword [eax], 0x80
370         jnz     @f
371         cmp     byte [eax+nameLength], 0
372         jz      .founddata
374         add     eax, [eax+sizeWithHeader]
375         jmp     .scandata
377 .founddata:
378         cmp     byte [eax+nonResidentFlag], 0
379         jz      .fail_free_frs
380         movzx   esi, word [eax+dataRunsOffset]
381         add     esi, eax
382         mov     edx, [eax+attributeAllocatedSize+4]
383         mov     eax, [eax+attributeAllocatedSize]
384         shrd    eax, edx, 9
385         mov     [ebp+NTFS.mftSize], eax
386         sub     esp, 10h
387         lea     ecx, [ebp+NTFS.mft_retrieval]
388         xor     edx, edx
389 .scanmcb:   ; load descriptions of fragments
390         call    ntfs_decode_mcb_entry
391         jnc     .scanmcbend
392         mov     eax, [esp]      ; block length
393         mov     [ecx], eax
394         add     edx, [esp+8]    ; block addr
395         mov     [ecx+4], edx
396         add     ecx, 8
397         jmp     .scanmcb
399 .scanmcbend:
400         add     esp, 10h
401         lea     eax, [ebp+NTFS.attrlist_buf]
402         cmp     eax, ecx
403         jc      @f
404         mov     eax, ecx
406         mov     [ebp+NTFS.mft_retrieval_end], eax
407 ; allocate index buffers
408         stdcall kernel_alloc, 2000h
409         test    eax, eax
410         jz      .fail_free_frs
411         mov     [ebp+NTFS.cur_index_buf], eax
412         add     eax, 1000h
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]
417         xor     edx, edx
418         div     [ebp+NTFS.sectors_per_cluster]
419         shr     eax, 3
420         mov     [ebp+NTFS.BitmapTotalSize], eax
421         add     eax, 7FFFh
422         and     eax, not 7FFFh
423         push    eax
424         call    alloc_kernel_space
425         test    eax, eax
426         jz      .failFreeIndex
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
432         shl     eax, 2
433         mov     [ebp+NTFS.BitmapStart], eax
434         shr     eax, 15
435         inc     eax
436         shl     eax, 3
437         push    eax
438         push    eax
439         shl     eax, 3
440         mov     [ebp+NTFS.cur_size], eax
441         call    alloc_pages
442         test    eax, eax
443         pop     ecx
444         jz      .failFreeBitmap
445         add     eax, 3
446         mov     ebx, [ebp+NTFS.BitmapBuffer]
447         call    commit_pages
448         mov     [ebp+NTFS.cur_iRecord], 6
449         mov     [ebp+NTFS.cur_attr], 0x80
450         mov     [ebp+NTFS.cur_offs], 0
451         call    ntfs_read_attr
452         jc      .failFreeBitmap
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
460         shl     eax, 9
461         stdcall kernel_alloc, eax
462         test    eax, eax
463         jz      .failFreeBitmap
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
469         call    ntfs_read_attr
470         mov     eax, [ebp+NTFS.cur_read]
471         cmp     eax, 4
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
480         mov     eax, ebp
481 .pop_exit:
482         pop     esi ebp ebx
483 .exit:
484         cmp     dword [esp+4], 0
485         jz      @f
486         sub     ebx, 512
488         ret
490 .failFreeBitmapMFT:
491         stdcall kernel_free, [ebp+NTFS.mftBitmapBuffer]
492 .failFreeBitmap:
493         stdcall kernel_free, [ebp+NTFS.BitmapBuffer]
494 .failFreeIndex:
495         mov     eax, [ebp+NTFS.cur_index_buf]
496         cmp     eax, [ebp+NTFS.secondIndexBuffer]
497         jc      @f
498         mov     eax, [ebp+NTFS.secondIndexBuffer]
500         stdcall kernel_free, eax
501 .fail_free_frs:
502         stdcall kernel_free, [ebp+NTFS.frs_buffer]
503 .fail_free:
504         stdcall kernel_free, ebp
505         xor     eax, eax
506         jmp     .pop_exit
508 ntfs_free:
509         push    ebx
510         mov     ebx, eax
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]
516         jc      @f
517         mov     eax, [ebx+NTFS.secondIndexBuffer]
519         stdcall kernel_free, eax
520         stdcall kernel_free, ebx
521         pop     ebx
522         ret
524 ntfs_lock:
525         lea     ecx, [ebp+NTFS.Lock]
526         jmp     mutex_lock
528 ntfs_unlock:
529         lea     ecx, [ebp+NTFS.Lock]
530         jmp     mutex_unlock
532 ntfs_read_attr:
533 ; [ebp+NTFS.bWriteAttr]=1 -> write attribute
534 ;   in:
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
540 ;   out:
541 ; [ebp+NTFS.cur_read] = bytes readen
542 ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
543         xor     eax, eax
544         pushad
545         and     [ebp+NTFS.cur_read], 0
546         cmp     [ebp+NTFS.cur_iRecord], 0
547         jnz     .nomft
548         cmp     [ebp+NTFS.cur_attr], 0x80
549         jnz     .nomft
550 ; precalculated part of $Mft $DATA
551         mov     eax, [ebp+NTFS.cur_offs]
552         xor     edx, edx
553         div     [ebp+NTFS.sectors_per_cluster]
554         mov     ebx, edx
555         mov     [ebp+NTFS.fragmentCount], 0
556 ; eax = VCN, ebx = offset in sectors from beginning of cluster
557         lea     esi, [ebp+NTFS.mft_retrieval]
558         sub     esi, 8
559 .mftscan:
560         add     esi, 8
561         cmp     esi, [ebp+NTFS.mft_retrieval_end]
562         jz      .nomft
563         mov     ecx, [esi+4]
564         sub     eax, [esi]
565         jnc     .mftscan
566         add     ecx, eax
567         add     ecx, [esi]
568         neg     eax
569         mul     [ebp+NTFS.sectors_per_cluster]
570         xchg    eax, ecx
571         mul     [ebp+NTFS.sectors_per_cluster]
572         sub     ecx, ebx
573         add     eax, ebx
574         mov     ebx, [ebp+NTFS.cur_buf]
575         cmp     ecx, [ebp+NTFS.cur_size]
576         jb      @f
577         mov     ecx, [ebp+NTFS.cur_size]
579         mov     [ebp+NTFS.LastRead], eax
580         mov     edi, ecx
581         call    fs_read64_sys
582         test    eax, eax
583         jnz     .errret
584         sub     [ebp+NTFS.cur_size], edi
585         add     [ebp+NTFS.cur_offs], edi
586         shl     edi, 9
587         add     [ebp+NTFS.cur_read], edi
588         add     [ebp+NTFS.cur_buf], edi
589         inc     [ebp+NTFS.fragmentCount]
590         xor     eax, eax
591         xor     ebx, ebx
592         cmp     [ebp+NTFS.cur_size], eax
593         jz      @f
594         jmp     .mftscan
596 .errret2_pop:
597         xor     eax, eax
598 .errret_pop:
599         pop     ecx
600         pop     ecx
601 .errret:
602         mov     [esp+28], eax
603         stc
605         popad
606         ret
608 .nomft:
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
616         jc      .errret
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
623         jz      @f
624         mov     eax, [eax+baseRecordReference]
625 .beginfindattr:
626         call    ntfs_read_file_record
627         jc      .errret
628         jmp     @f
630 .newAttribute:
631         pushad
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]
637         add     eax, ecx
638         mov     ecx, [ebp+NTFS.cur_attr]
639         and     [ebp+NTFS.attr_offs], 0
640 .scanattr:
641         cmp     dword [eax], -1
642         jz      .scandone
643         cmp     dword [eax], ecx
644         jz      .okattr
645         cmp     [ebp+NTFS.attr_iBaseRecord], -1
646         jnz     .scancont
647         cmp     dword [eax], 0x20       ; $ATTR_LIST
648         jnz     .scancont
649         mov     [ebp+NTFS.attr_list], eax
650         jmp     .scancont
652 .okattr:
653 ; ignore named $DATA attributes (aka NTFS streams)
654         cmp     ecx, 0x80
655         jnz     @f
656         cmp     byte [eax+nameLength], 0
657         jnz     .scancont
659         mov     [ebp+NTFS.attr_offs], eax
660 .scancont:
661         add     eax, [eax+sizeWithHeader]
662         jmp     .scanattr
664 .continue:
665         pushad
666         and     [ebp+NTFS.cur_read], 0
667 .scandone:
668 ; c) Check for required offset and length
669         mov     ecx, [ebp+NTFS.attr_offs]
670         jecxz   .noattr
671         push    [ebp+NTFS.cur_size]
672         push    [ebp+NTFS.cur_read]
673         call    .doreadattr
674         pop     edx
675         pop     ecx
676         jc      .ret
677         cmp     [ebp+NTFS.bCanContinue], 0
678         jz      .ret
679         sub     edx, [ebp+NTFS.cur_read]
680         neg     edx
681         shr     edx, 9
682         sub     ecx, edx
683         mov     [ebp+NTFS.cur_size], ecx
684         jz      .ret
685 .noattr:
686         cmp     [ebp+NTFS.cur_attr], 0x20
687         jz      @f
688         mov     ecx, [ebp+NTFS.attr_list]
689         test    ecx, ecx
690         jnz     .lookattr
691         and     dword [esp+28], 0
692         cmp     [ebp+NTFS.attr_offs], 1     ; define CF
693 .ret:
694         popad
695         ret
697 .lookattr:
698 ; required attribute or required offset was not found in base record;
699 ; it may be present in auxiliary records;
700 ; scan $ATTR_LIST
701         mov     eax, [ebp+NTFS.attr_iBaseRecord]
702         cmp     eax, -1
703         jz      @f
704         call    ntfs_read_file_record
705         jc      .errret
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
720         jnz     @f
721         lea     eax, [ebp+NTFS.attrlist_mft_buf]
723         mov     [ebp+NTFS.cur_buf], eax
724         push    eax
725         call    .doreadattr
726         pop     esi
727         mov     edx, 1
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]
735         jc      .errret
736         or      edi, -1
737         lea     ecx, [ecx+esi-1Ah]
738 .scanliststart:
739         push    ecx
740         mov     eax, [ebp+NTFS.cur_attr]
741 .scanlist:
742         cmp     esi, [esp]
743         jae     .scanlistdone
744         cmp     eax, [esi]
745         jz      @f
746 .scanlistcont:
747         movzx   ecx, word [esi+4]
748         add     esi, ecx
749         jmp     .scanlist
752 ; ignore named $DATA attributes (aka NTFS streams)
753         cmp     eax, 0x80
754         jnz     @f
755         cmp     byte [esi+6], 0
756         jnz     .scanlistcont
758         push    eax
759         mov     eax, [esi+8]
760         test    eax, eax
761         jnz     .testf
762         cmp     dword [ebp+NTFS.attr_size+4], -1
763         jnz     .testfz
764 ; if attribute is in auxiliary records, its size is defined only in first
765         mov     eax, [esi+10h]
766         call    ntfs_read_file_record
767         jc      .errret_pop
768         mov     eax, [ebp+NTFS.frs_buffer]
769         movzx   ecx, word [eax+14h]
770         add     eax, ecx
771         mov     ecx, [ebp+NTFS.cur_attr]
773         cmp     dword [eax], -1
774         jz      .errret2_pop
775         cmp     dword [eax], ecx
776         jz      @f
777 .l1:
778         add     eax, [eax+4]
779         jmp     @b
782         cmp     eax, 0x80
783         jnz     @f
784         cmp     byte [eax+9], 0
785         jnz     .l1
787         cmp     byte [eax+8], 0
788         jnz     .sdnores
789         mov     eax, [eax+10h]
790         mov     dword [ebp+NTFS.attr_size], eax
791         and     dword [ebp+NTFS.attr_size+4], 0
792         jmp     .testfz
794 .sdnores:
795         mov     ecx, [eax+30h]
796         mov     dword [ebp+NTFS.attr_size], ecx
797         mov     ecx, [eax+34h]
798         mov     dword [ebp+NTFS.attr_size+4], ecx
799 .testfz:
800         xor     eax, eax
801 .testf:
802         imul    eax, [ebp+NTFS.sectors_per_cluster]
803         cmp     eax, [ebp+NTFS.cur_offs]
804         pop     eax
805         ja      @f
806         mov     edi, [esi+10h]  ; keep previous iRecord
807         jmp     .scanlistcont
810         pop     ecx
811 .scanlistfound:
812         cmp     edi, -1
813         jz      .ret
814         mov     eax, [ebp+NTFS.cur_iRecord]
815         mov     [ebp+NTFS.attr_iBaseRecord], eax
816         mov     eax, edi
817         jmp     .beginfindattr
819 .scanlistdone:
820         pop     ecx
821         sub     ecx, ebp
822         sub     ecx, NTFS.attrlist_buf-1Ah
823         cmp     [ebp+NTFS.cur_iRecord], 0
824         jnz     @f
825         sub     ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
827         cmp     ecx, 0x400
828         jnz     .scanlistfound
829         inc     edx
830         push    esi edi
831         lea     esi, [ebp+NTFS.attrlist_buf+0x200]
832         lea     edi, [ebp+NTFS.attrlist_buf]
833         cmp     [ebp+NTFS.cur_iRecord], 0
834         jnz     @f
835         lea     esi, [ebp+NTFS.attrlist_mft_buf+0x200]
836         lea     edi, [ebp+NTFS.attrlist_mft_buf]
838         mov     ecx, 0x200/4
839         rep movsd
840         mov     eax, edi
841         pop     edi esi
842         sub     esi, 0x200
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]
855         push    esi edx edi
856         call    .doreadattr
857         pop     edi edx esi
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]
865         jc      .errret
866         lea     ecx, [ecx+ebp+NTFS.attrlist_buf+0x200-0x1A]
867         cmp     [ebp+NTFS.cur_iRecord], 0
868         jnz     .scanliststart
869         add     ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
870         jmp     .scanliststart
872 .doreadattr:
873         mov     [ebp+NTFS.bCanContinue], 0
874         cmp     byte [ecx+nonResidentFlag], 0
875         jnz     .nonresident
876         mov     eax, [ecx+sizeWithoutHeader]
877         mov     esi, eax
878         mov     edx, [ebp+NTFS.cur_offs]
879         shr     eax, 9
880         cmp     eax, edx
881         jb      .okret
882         shl     edx, 9
883         sub     esi, edx
884         movzx   eax, word [ecx+attributeOffset]
885         add     edx, eax
886         add     edx, ecx        ; edx -> data
887         mov     eax, [ebp+NTFS.cur_size]
888         cmp     eax, (0xFFFFFFFF shr 9)+1
889         jbe     @f
890         mov     eax, (0xFFFFFFFF shr 9)+1
892         shl     eax, 9
893         cmp     eax, esi
894         jbe     @f
895         mov     eax, esi
897 ; eax = length, edx -> data
898         mov     [ebp+NTFS.cur_read], eax
899         mov     ecx, eax
900         mov     eax, edx
901         mov     ebx, [ebp+NTFS.cur_buf]
902         call    memmove
903         and     [ebp+NTFS.cur_size], 0      ; CF=0
904         ret
906 .nonresident:
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]
910         cmp     edx, -1
911         jnz     @f
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
917         add     eax, 0x1FF
918         adc     edx, 0
919         shrd    eax, edx, 9
920         sub     eax, [ebp+NTFS.cur_offs]
921         ja      @f
922 ; return with nothing read
923         and     [ebp+NTFS.cur_size], 0
924 .okret:
925         clc
926         ret
929 ; reduce read length
930         and     [ebp+NTFS.cur_tail], 0
931         cmp     [ebp+NTFS.cur_size], eax
932         jb      @f
933         mov     [ebp+NTFS.cur_size], eax
934         mov     eax, dword [ebp+NTFS.attr_size]
935         and     eax, 0x1FF
936         mov     [ebp+NTFS.cur_tail], eax
938         mov     eax, [ebp+NTFS.cur_offs]
939         xor     edx, edx
940         div     [ebp+NTFS.sectors_per_cluster]
941         sub     eax, [ecx+firstVCN]
942         jb      .okret
943         mov     ebx, edx
944 ; eax = starting cluster, ebx = sector in the cluster
945         cmp     [ebp+NTFS.cur_attr], 0x80
946         jnz     .sys
947         cmp     [ebp+NTFS.cur_iRecord], 0
948         jz      .sys
949         push    fs_read64_app
950         cmp     [ebp+NTFS.bWriteAttr], 1
951         jnz     @f
952         mov     dword[esp], fs_write64_app
953         jmp     @f
955 .sys:
956         push    fs_read64_sys
958         sub     esp, 10h
959         movzx   esi, word [ecx+dataRunsOffset]
960         add     esi, ecx
961         xor     edi, edi
962         mov     [ebp+NTFS.fragmentCount], 0
963 .readloop:
964         call    ntfs_decode_mcb_entry
965         jnc     .break
966         add     edi, [esp+8]
967         sub     eax, [esp]
968         jae     .readloop
969         mov     ecx, edi
970         add     ecx, eax
971         add     ecx, [esp]
972         neg     eax
973         mul     [ebp+NTFS.sectors_per_cluster]
974         xchg    eax, ecx
975         mul     [ebp+NTFS.sectors_per_cluster]
976         sub     ecx, ebx
977         add     eax, ebx
978         mov     ebx, [ebp+NTFS.cur_buf]
979         cmp     ecx, [ebp+NTFS.cur_size]
980         jb      @f
981         mov     ecx, [ebp+NTFS.cur_size]
983         mov     [ebp+NTFS.LastRead], eax
984         push    ecx
985         call    dword[esp+14h]
986         pop     ecx
987         test    eax, eax
988         jnz     .errread2
989         sub     [ebp+NTFS.cur_size], ecx
990         add     [ebp+NTFS.cur_offs], ecx
991         shl     ecx, 9
992         add     [ebp+NTFS.cur_read], ecx
993         add     [ebp+NTFS.cur_buf], ecx
994         inc     [ebp+NTFS.fragmentCount]
995         xor     eax, eax
996         xor     ebx, ebx
997         cmp     [ebp+NTFS.cur_size], 0
998         jnz     .readloop
999         add     esp, 14h
1000         mov     eax, [ebp+NTFS.cur_tail]
1001         test    eax, eax
1002         jz      @f
1003         sub     eax, 0x200
1004         add     [ebp+NTFS.cur_read], eax
1006         clc
1007         ret
1009 .errread2:
1010         add     esp, 14h
1011         stc
1012         ret
1014 .break:
1015         add     esp, 14h        ; CF=0
1016         mov     [ebp+NTFS.bCanContinue], 1
1017         ret
1019 ntfs_read_file_record:
1020 ; in: eax = iRecord
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]
1024         push    ecx edx
1025         mov     ecx, [ebp+NTFS.frs_size]
1026         mul     ecx
1027         shrd    eax, edx, 9
1028         shr     edx, 9
1029         jnz     .errret
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
1044         shr     ecx, 9
1045         mov     [ebp+NTFS.cur_size], ecx
1046         mov     eax, [ebp+NTFS.frs_buffer]
1047         mov     [ebp+NTFS.cur_buf], eax
1048         call    ntfs_read_attr
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]
1061         jc      .ret
1062         cmp     edx, [ebp+NTFS.frs_size]
1063         jnz     .errret
1064         mov     eax, [ebp+NTFS.LastRead]
1065         mov     [ebp+NTFS.mftLastRead], eax
1066         mov     eax, [ebp+NTFS.frs_buffer]
1067         cmp     dword [eax], 'FILE'
1068         jnz     .errret
1069         push    ebx
1070         mov     ebx, eax
1071         call    ntfs_restore_usa_frs
1072         pop     ebx
1073         jc      .errret
1074 .ret:
1075         pop     edx ecx
1076         ret
1078 .errret:
1079         pop     edx ecx
1080         xor     eax, eax
1081         stc
1082         ret
1084 ntfs_restore_usa_frs:
1085         mov     eax, [ebp+NTFS.frs_size]
1086 ntfs_restore_usa:
1087 ;   in:
1088 ; ebx -> record
1089 ; eax = size in bytes
1090         pushad
1091         shr     eax, 9
1092         mov     ecx, eax
1093         inc     eax
1094         cmp     [ebx+updateSequenceSize], ax
1095         jnz     .err
1096         movzx   eax, word [ebx+updateSequenceOffset]
1097         lea     esi, [eax+ebx]
1098         lodsw
1099         mov     edx, eax
1100         lea     edi, [ebx+0x1FE]
1102         cmp     [edi], dx
1103         jnz     .err
1104         lodsw
1105         stosw
1106         add     edi, 0x1FE
1107         loop    @b
1108         popad
1109         clc
1110         ret
1112 .err:
1113         popad
1114         stc
1115         ret
1117 ntfs_decode_mcb_entry:
1118 ;   in:
1119 ; esi -> MCB entry
1120 ; esp -> buffer (16 bytes)
1121 ;   out:
1122 ; esi -> next MCB entry
1123 ; esp -> data run size
1124 ; esp+8 -> cluster (delta)
1125 ; CF=0 -> MCB end
1126         push    eax ecx edi
1127         lea     edi, [esp+16]
1128         xor     eax, eax
1129         lodsb
1130         test    al, al
1131         jz      .end
1132         mov     ecx, eax
1133         and     ecx, 0xF
1134         cmp     ecx, 8
1135         ja      .end
1136         push    ecx
1137         rep movsb
1138         pop     ecx
1139         sub     ecx, 8
1140         neg     ecx
1141         cmp     byte [esi-1], 80h
1142         jae     .end
1143         push    eax
1144         xor     eax, eax
1145         rep stosb
1146         pop     ecx
1147         shr     ecx, 4
1148         cmp     ecx, 8
1149         ja      .end
1150         push    ecx
1151         rep movsb
1152         pop     ecx
1153         sub     ecx, 8
1154         neg     ecx
1155         cmp     byte [esi-1], 80h
1156         cmc
1157         sbb     eax, eax
1158         rep stosb
1159         stc
1160 .end:
1161         pop     edi ecx eax
1162         ret
1164 ntfs_find_lfn:
1165 ; in: esi -> path string in UTF-8
1166 ;   out:
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
1178 .doit2:
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
1185         call    ntfs_read_attr
1186         mov     eax, 0
1187         jc      .ret
1188         cmp     [ebp+NTFS.cur_read], 0x20
1189         jc      .ret
1190         push    esi
1191         pushad
1192         mov     esi, [ebp+NTFS.cur_index_buf]
1193         mov     eax, [esi+indexRecordSize]
1194         shr     eax, 9
1195         cmp     [ebp+NTFS.cur_index_size], eax
1196         jc      .realloc
1197         mov     [ebp+NTFS.cur_size], eax
1198         mov     al, [esi+indexRecordSizeClus]
1199         mov     [ebp+NTFS.cur_subnode_size], eax
1200         add     esi, rootNode
1201         mov     eax, [esi+nodeRealSize]
1202         add     eax, rootNode
1203         cmp     [ebp+NTFS.cur_read], eax
1204         jc      .err
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]
1211 .scanloopint:
1212         push    esi
1213         test    byte [esi+indexFlags], 2
1214         jnz     .subnode
1215         movzx   ecx, byte [esi+fileNameLength]
1216         lea     edi, [esi+fileName]
1217         mov     esi, [esp+8]
1219         call    utf8to16
1220         cmp     ax, '/'
1221         jz      .subnode
1222         call    utf16toUpper
1223         push    eax
1224         mov     ax, [edi]
1225         call    utf16toUpper
1226         cmp     [esp], ax
1227         pop     eax
1228         jc      .subnode
1229         jnz     .scanloopcont
1230         add     edi, 2
1231         loop    @b
1232         call    utf8to16
1233         cmp     ax, '/'
1234         jz      .found
1235         test    ax, ax
1236         jz      .found
1237 .scanloopcont:
1238         pop     esi
1239         movzx   eax, word [esi+indexAllocatedSize]
1240         add     esi, eax
1241         jmp     .scanloopint
1243 .realloc:
1244         mov     edi, eax
1245         mov     eax, [esi+indexRecordSize]
1246         shl     eax, 1
1247         stdcall kernel_alloc, eax
1248         test    eax, eax
1249         jz      .err
1250         mov     edx, [ebp+NTFS.cur_index_buf]
1251         cmp     edx, [ebp+NTFS.secondIndexBuffer]
1252         jc      @f
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
1260         popad
1261         pop     eax
1262         jmp     .doit2
1264 .notfound:
1265         mov     [esp+28], esi
1266 .err:
1267         popad
1268         stc
1269 .ret2:
1270         pop     esi
1271 .ret:
1272         ret
1274 .subnode:
1275         pop     esi
1276         test    byte [esi+indexFlags], 1
1277         jz      .notfound
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]
1284         push    edx
1285         cmp     edx, [ebp+NTFS.cur_subnode_size]
1286         jz      @f
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
1296         pop     eax
1297         mov     [ebp+NTFS.cur_size], eax
1298         shl     eax, 9
1299         cmp     [ebp+NTFS.cur_read], eax
1300         jnz     .err
1301         cmp     dword [esi], 'INDX'
1302         jnz     .err
1303         mov     ebx, esi
1304         call    ntfs_restore_usa
1305         jc      .err
1306         add     esi, recordNode
1307         jmp     .scanloop
1309 .found:
1310         mov     [esp+8], esi
1311         pop     eax
1312         mov     [esp+28], eax
1313         mov     eax, [eax+fileRecordReference]
1314         mov     [ebp+NTFS.cur_iRecord], eax
1315         popad
1316         cmp     byte [esi-1], 0
1317         jz      .ret2
1318         pop     eax
1319         jmp     .doit2
1321 ;----------------------------------------------------------------
1322 ntfs_ReadFile:
1323         call    ntfs_lock
1324         call    ntfs_find_lfn
1325         jc      ntfsNotFound
1326         mov     [ebp+NTFS.cur_attr], 0x80   ; $DATA
1327         and     [ebp+NTFS.cur_offs], 0
1328         and     [ebp+NTFS.cur_size], 0
1329         call    ntfs_read_attr
1330         jc      ntfsDenied
1331         xor     eax, eax
1332         push    eax
1333         cmp     dword [ebx+8], 0x200
1334         jnc     .eof
1335         mov     ecx, [ebx+12]
1336         mov     edx, [ebx+16]
1337         mov     eax, [ebx+4]
1338         test    eax, 0x1FF
1339         jz      .alignedstart
1340         push    edx
1341         mov     edx, [ebx+8]
1342         shrd    eax, edx, 9
1343         pop     edx
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
1349         mov     eax, [ebx+4]
1350         and     eax, 0x1FF
1351         lea     esi, [ebp+NTFS.bitmap_buf+eax]
1352         sub     eax, [ebp+NTFS.cur_read]
1353         jae     .eof
1354         neg     eax
1355         push    ecx
1356         cmp     ecx, eax
1357         jb      @f
1358         mov     ecx, eax
1360         mov     [esp+4], ecx
1361         mov     edi, edx
1362         rep movsb
1363         mov     edx, edi
1364         pop     ecx
1365         sub     ecx, [esp]
1366         jz      .retok
1367         cmp     [ebp+NTFS.cur_read], 0x200
1368         jnz     .eof
1369 .alignedstart:
1370         mov     eax, [ebx+4]
1371         push    edx
1372         mov     edx, [ebx+8]
1373         add     eax, 511
1374         adc     edx, 0
1375         shrd    eax, edx, 9
1376         pop     edx
1377         mov     [ebp+NTFS.cur_offs], eax
1378         mov     [ebp+NTFS.cur_buf], edx
1379         mov     eax, ecx
1380         shr     eax, 9
1381         mov     [ebp+NTFS.cur_size], eax
1382         add     eax, [ebp+NTFS.cur_offs]
1383         push    eax
1384         call    ntfs_read_attr.continue
1385         pop     [ebp+NTFS.cur_offs]
1386         mov     eax, [ebp+NTFS.cur_read]
1387         add     [esp], eax
1388         mov     eax, ecx
1389         and     eax, not 0x1FF
1390         cmp     [ebp+NTFS.cur_read], eax
1391         jnz     .eof
1392         and     ecx, 0x1FF
1393         jz      .retok
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
1400         jb      @f
1401         mov     [ebp+NTFS.cur_read], ecx
1403         xchg    ecx, [ebp+NTFS.cur_read]
1404         push    ecx
1405         mov     edi, edx
1406         lea     esi, [ebp+NTFS.bitmap_buf]
1407         add     [esp+4], ecx
1408         rep movsb
1409         pop     ecx
1410         cmp     ecx, [ebp+NTFS.cur_read]
1411         jnz     .eof
1412 .retok:
1413         pushd   0
1414 .ret:
1415         call    ntfs_unlock
1416         pop     eax ebx
1417         ret
1419 .eof:
1420         push    ERROR_END_OF_FILE
1421         jmp     .ret
1423 ;----------------------------------------------------------------
1424 ntfs_ReadFolder:
1425         call    ntfs_lock
1426         mov     [ebp+NTFS.cur_iRecord], 5   ; root directory
1427         cmp     byte [esi], 0
1428         jz      @f
1429         call    ntfs_find_lfn
1430         jc      ntfsNotFound
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
1437         call    ntfs_read_attr
1438         jc      ntfsFail
1439         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
1440 .doit:
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
1446         jc      ntfsFail
1447         cmp     [ebp+NTFS.cur_read], 0x20
1448         jc      ntfsFail
1449         mov     esi, [ebp+NTFS.cur_index_buf]
1450         mov     eax, [esi+indexRecordSize]
1451         shr     eax, 9
1452         cmp     [ebp+NTFS.cur_index_size], eax
1453         jc      .realloc
1454         mov     [ebp+NTFS.cur_subnode_size], eax
1455         add     esi, rootNode
1456         mov     eax, [esi+nodeRealSize]
1457         add     eax, rootNode
1458         cmp     [ebp+NTFS.cur_read], eax
1459         jc      ntfsFail
1460         mov     edi, [ebx+16]
1461         mov     ecx, [ebx+12]
1462         pushd   [ebx]
1463         pushd   [ebx+8]     ; read ANSI/UNICODE name
1464         push    edi
1465         mov     edx, esp
1466         mov     ebx, [ebx+4]
1467 ; init header
1468         xor     eax, eax
1469         mov     [edi+8], eax
1470         mov     [edi+4], eax
1471         inc     eax
1472         mov     [edi], eax      ; version
1473         add     edi, 32
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
1478         jz      .skip_specials
1479 ; dot and dotdot entries
1480         push    esi
1481         xor     esi, esi
1482         call    .add_special_entry
1483         inc     esi
1484         call    .add_special_entry
1485         pop     esi
1486 .skip_specials:
1487 ; at first, dump index root
1488         add     esi, [esi+indexOffset]
1489 .dump_root:
1490         test    byte [esi+indexFlags], 2
1491         jnz     .dump_root_done
1492         call    .add_entry
1493         movzx   eax, word [esi+indexAllocatedSize]
1494         add     esi, eax
1495         jmp     .dump_root
1497 .realloc:
1498         mov     edi, eax
1499         mov     eax, [esi+indexRecordSize]
1500         shl     eax, 1
1501         stdcall kernel_alloc, eax
1502         test    eax, eax
1503         jz      ntfsFail
1504         mov     edx, [ebp+NTFS.cur_index_buf]
1505         cmp     edx, [ebp+NTFS.secondIndexBuffer]
1506         jc      @f
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
1514         jmp     .doit
1516 .dump_root_done:
1517 ; now dump all subnodes
1518         push    ecx edi
1519         lea     edi, [ebp+NTFS.bitmap_buf]
1520         mov     [ebp+NTFS.cur_buf], edi
1521         mov     ecx, 0x400/4
1522         xor     eax, eax
1523         rep stosd
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
1528         pop     edi ecx
1529         push    0       ; save offset in $BITMAP attribute
1530         and     [ebp+NTFS.cur_offs], 0
1531 .dumploop:
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]
1538         push    eax
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]
1544         shl     eax, 9
1545         cmp     [ebp+NTFS.cur_read], eax
1546         jnz     .done
1547         push    eax
1548         mov     eax, [ebp+NTFS.cur_offs]
1549         and     eax, 0x400*8-1
1550         bt      dword [ebp+NTFS.bitmap_buf], eax
1551         pop     eax
1552         jnc     .dump_subnode_done
1553         cmp     dword [esi], 'INDX'
1554         jnz     .dump_subnode_done
1555         push    ebx
1556         mov     ebx, esi
1557         call    ntfs_restore_usa
1558         pop     ebx
1559         jc      .dump_subnode_done
1560         add     esi, recordNode
1561         add     esi, [esi+indexOffset]
1562 .dump_subnode:
1563         test    byte [esi+indexFlags], 2
1564         jnz     .dump_subnode_done
1565         call    .add_entry
1566         movzx   eax, word [esi+indexAllocatedSize]
1567         add     esi, eax
1568         jmp     .dump_subnode
1570 .dump_subnode_done:
1571         inc     [ebp+NTFS.cur_offs]
1572         test    [ebp+NTFS.cur_offs], 0x400*8-1
1573         jnz     .dumploop
1574         mov     [ebp+NTFS.cur_attr], 0xB0
1575         push    ecx edi
1576         lea     edi, [ebp+NTFS.bitmap_buf]
1577         mov     [ebp+NTFS.cur_buf], edi
1578         mov     ecx, 0x400/4
1579         xor     eax, eax
1580         rep stosd
1581         pop     edi ecx
1582         pop     eax
1583         push    [ebp+NTFS.cur_offs]
1584         inc     eax
1585         mov     [ebp+NTFS.cur_offs], eax
1586         mov     [ebp+NTFS.cur_size], 2
1587         push    eax
1588         call    ntfs_read_attr.newAttribute
1589         pop     eax
1590         pop     [ebp+NTFS.cur_offs]
1591         push    eax
1592         jmp     .dumploop
1594 .done:
1595         pop     eax
1596         pop     eax
1597         mov     ebx, [eax+4]
1598         pop     eax
1599         pop     eax
1600         test    eax, eax
1601         jz      .ret
1602         xor     eax, eax
1603         dec     ecx
1604         js      @f
1605         mov     al, ERROR_END_OF_FILE
1607         push    eax
1608         call    ntfs_unlock
1609         pop     eax
1610         ret
1612 .add_special_entry:
1613         mov     eax, [edx]
1614         inc     dword [eax+8]   ; new file found
1615         dec     ebx
1616         jns     .ret
1617         dec     ecx
1618         js      .ret
1619         inc     dword [eax+4]   ; new file block copied
1620         mov     eax, [edx+4]
1621         mov     [edi+4], eax
1622         mov     eax, 0x10
1623         stosd
1624         scasd
1625         push    ebx ecx edx
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
1635         pop     edx ecx ebx
1636         xor     eax, eax
1637         stosd
1638         stosd
1639         mov     al, '.'
1640         push    edi ecx
1641         lea     ecx, [esi+1]
1642         cmp     dword[edi-36], 2
1643         jz      .utf16sp
1644         rep stosb
1645         mov     byte [edi], 0
1646         pop     ecx edi
1647         cmp     dword[edi-36], 3
1648         jz      @f
1649         add     edi, 264
1650         ret
1652 .utf16sp:
1653         rep stosw
1654         mov     word [edi], 0
1655         pop     ecx edi
1657         add     edi, 520
1658 .ret:
1659         ret
1661 .add_entry:
1662 ; do not return DOS 8.3 names
1663         cmp     byte [esi+namespace], 2
1664         jz      .ret
1665 ; do not return system files
1666         cmp     dword[esi+fileRecordReference], 16
1667         jb      .ret
1668         cmp     byte [esi+fileNameLength], 0
1669         jz      .ret
1670         mov     eax, [edx]
1671         inc     dword [eax+8]   ; new file found
1672         dec     ebx
1673         jns     .ret
1674         dec     ecx
1675         js      .ret
1676         inc     dword [eax+4]   ; new file block copied
1677         mov     eax, [edx+4]    ; flags
1678         call    ntfs_direntry_to_bdfe
1679         push    ecx esi edi
1680         movzx   ecx, byte [esi+fileNameLength]
1681         add     esi, fileName
1682         cmp     dword[edi-36], 2
1683         jz      .utf16
1684         cmp     dword[edi-36], 3
1685         jz      .utf8
1687         lodsw
1688         call    uni2ansi_char
1689         stosb
1690         loop    @b
1691         mov     byte [edi], 0
1692         pop     edi esi ecx
1693         add     edi, 264
1694         ret
1696 .utf8:
1697         push    ecx
1698         mov     cx, 519
1700         lodsw
1701         call    UTF16to8
1702         js      @f
1703         dec     dword[esp]
1704         jnz     @b
1706         mov     byte [edi], 0
1707         pop     edi
1709         pop     edi esi ecx
1710         add     edi, 520
1711         ret
1713 .utf16:
1714         rep movsw
1715         mov     word [edi], 0
1716         jmp     @b
1718 ntfs_direntry_to_bdfe:
1719         mov     [edi+4], eax    ; ANSI/UNICODE name
1720         mov     eax, [esi+fileFlags]
1721         test    eax, 0x10000000
1722         jz      @f
1723         and     eax, not 0x10000000
1724         or      al, 0x10
1726         stosd
1727         scasd
1728         push    ebx ecx edx
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
1738         pop     edx ecx ebx
1739         mov     eax, [esi+fileRealSize]
1740         stosd
1741         mov     eax, [esi+fileRealSize+4]
1742         stosd
1743         ret
1745 ntfs_datetime_to_bdfe:
1746 ; in: edx:eax = seconds since 01.01.1601 x10000000
1747 ; edi -> data block
1748 ; out: edi = edi+8
1749         sub     eax, 3365781504
1750         sbb     edx, 29389701
1751         mov     ecx, 10000000
1752         cmp     edx, ecx
1753         jc      @f
1754         xor     edx, edx
1756         div     ecx
1757         jmp     fsTime2bdfe
1759 ;----------------------------------------------------------------
1760 ntfs_GetFileInfo:
1761         mov     edi, [ebx+16]
1762         cmp     byte [esi], 0
1763         jz      .volume
1764         call    ntfs_lock
1765         call    ntfs_find_lfn
1766         jnc     .found
1767         test    eax, eax
1768         jz      ntfsFail
1769         jmp     ntfsNotFound
1771 .found:
1772         mov     esi, eax
1773         xor     eax, eax
1774         call    ntfs_direntry_to_bdfe
1775 .end:
1776         call    ntfs_unlock
1777         xor     eax, eax
1779         ret
1781 .volume:
1782         mov     eax, dword [ebp+NTFS.Length]
1783         mov     edx, dword [ebp+NTFS.Length+4]
1784         shld    edx, eax, 9
1785         shl     eax, 9
1786         mov     [edi+36], edx
1787         mov     [edi+32], eax
1788         mov     eax, [ebx+8]
1789         mov     byte [edi], 8
1790         mov     [edi+4], eax
1791         test    eax, eax
1792         jz      @b
1793         call    ntfs_lock
1794         add     edi, 40
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
1800         call    ntfs_read_attr
1801         jc      ntfsFail
1802         mov     ecx, [ebp+NTFS.cur_read]
1803         mov     [edi+ecx], ax
1804         cmp     byte [ebx+8], 2
1805         jz      .end
1806         shr     ecx, 1
1807         jz      .end
1808         mov     esi, edi
1809         cmp     byte [ebx+8], 3
1810         jnz     @f
1811         shl     ecx, 1
1812         call    UTF16to8_string
1813         mov     byte [edi], 0
1814         jmp     .end
1817         lodsw
1818         call    uni2ansi_char
1819         stosb
1820         loop    @b
1821         mov     byte [edi], 0
1822         jmp     .end
1824 ;----------------------------------------------------------------
1825 ntfs_CreateFolder:
1826         mov     [ebp+NTFS.bFolder], 1
1827         jmp     @f
1829 ntfs_CreateFile:
1830         mov     [ebp+NTFS.bFolder], 0
1831 @@: ; 1. Search file
1832         call    ntfs_lock
1833         call    ntfs_find_lfn
1834         jc      .notFound
1835 ; found, rewrite
1836         cmp     [ebp+NTFS.cur_iRecord], 16
1837         jc      ntfsDenied
1838         cmp     [ebp+NTFS.bFolder], 1
1839         jz      .folder
1840         test    byte [eax+fileFlags], 1
1841         jnz     ntfsDenied
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'
1847         jz      @f
1848         mov     esi, [ebp+NTFS.frs_buffer]
1849         mov     ecx, [esi+recordRealSize]
1850         shr     ecx, 2
1851         rep movsd
1852         mov     esi, [ebp+NTFS.attr_offs]
1853         mov     cl, [esi+attributeOffset]
1854         sub     esi, [ebp+NTFS.frs_buffer]
1855         add     eax, ecx
1856         add     eax, esi
1858         mov     edi, eax
1859         mov     eax, [ebx+12]
1860         mov     [edi+fileRealSize], eax
1861         mov     dword [edi+fileRealSize+4], 0
1862         push    ebx eax
1863         call    ntfsGetTime
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
1870         pop     edx ebx
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
1876         call    ntfs_read_attr
1877         jc      ntfsFail
1878         mov     esi, edi
1879         mov     edi, [ebp+NTFS.frs_buffer]
1880         cmp     word [edi+baseRecordReuse], 0
1881         jnz     ntfsUnsupported     ; auxiliary record
1882         mov     al, [edi+attributeOffset]
1883         add     edi, eax
1884         mov     al, [edi+attributeOffset]
1885         add     edi, eax
1886         mov     ecx, 6
1887         add     esi, fileModified
1888         add     edi, 8
1889         rep movsd
1890         mov     eax, edx
1891         xor     edx, edx
1892         mov     ecx, [ebp+NTFS.attr_offs]
1893         cmp     word [ecx+attributeFlags], 0
1894         jnz     ntfsUnsupported
1895         push    ebx
1896         cmp     byte [ecx+nonResidentFlag], 0
1897         jz      @f
1898         cmp     [ecx+attributeRealSize+4], edx
1899         jnz     @f
1900         cmp     [ecx+attributeRealSize], eax
1901         jz      ntfs_WriteFile.writeNode
1903         jmp     ntfs_WriteFile.resizeAttribute
1905 .folder:
1906         bt      dword [eax+fileFlags], 28
1907         jnc     ntfsDenied
1908         push    0
1909         jmp     ntfsOut
1911 .notFound:  ; create
1912         test    eax, eax
1913         jz      ntfsFail
1914         cmp     [ebp+NTFS.fragmentCount], 1
1915         jnz     ntfsUnsupported     ; record fragmented
1916 ; 2. Prepare directory record
1917         mov     edi, esi
1918         mov     edx, eax
1919         xor     ecx, ecx
1920 @@:         ; count characters
1921         call    utf8to16
1922         cmp     ax, '/'
1923         jz      ntfsNotFound    ; path folder not found
1924         inc     ecx
1925         test    ax, ax
1926         jnz     @b
1927         dec     ecx
1928         push    ecx     ; name length in chars
1929         push    edi
1930         shl     ecx, 1
1931         add     ecx, fileName+7
1932         and     ecx, not 7
1933         mov     edi, [ebp+NTFS.cur_index_buf]
1934         mov     eax, [ebx+12]
1935         mov     [ebp+NTFS.fileRealSize], eax
1936         mov     eax, [ebx+16]
1937         mov     [ebp+NTFS.fileDataBuffer], eax
1938         push    ecx     ; index length
1939         mov     eax, edx
1940         mov     edx, ecx
1941         cmp     dword [edi], 'INDX'
1942         jz      .indexRecord
1943         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
1944         mov     ecx, [esi+recordRealSize]
1945         add     edx, ecx
1946         cmp     [esi+recordAllocatedSize], edx
1947         jc      .growTree
1948         mov     [esi+recordRealSize], edx
1949         shr     ecx, 2
1950         rep movsd
1951         mov     edi, [ebp+NTFS.indexRoot]
1952         sub     edi, [ebp+NTFS.frs_buffer]
1953         add     edi, [ebp+NTFS.cur_index_buf]
1954         mov     esi, [esp]
1955         add     [edi+sizeWithHeader], esi
1956         add     [edi+sizeWithoutHeader], esi
1957         mov     cl, [edi+attributeOffset]
1958         add     edi, ecx
1959         add     [edi+rootNode+nodeRealSize], esi
1960         add     [edi+rootNode+nodeAllocatedSize], esi
1961         sub     eax, [ebp+NTFS.cur_index_buf]
1962         add     eax, edi
1963         mov     edi, [ebp+NTFS.cur_index_buf]
1964         jmp     .common
1966 .growTree:  ; create indexRecord
1967         mov     edi, [ebp+NTFS.cur_index_buf]
1968         mov     ecx, 10
1969         xor     eax, eax
1970         rep stosd
1971         mov     esi, [ebp+NTFS.indexRoot]
1972         mov     al, [esi+attributeOffset]
1973         add     esi, eax
1974         rdtsc
1975         stosw
1976         mov     eax, [esi+indexRecordSize]
1977         cmp     eax, [ebp+NTFS.frs_size]
1978         jc      .errorPop3
1979         shr     eax, 9
1980         inc     eax
1981         mov     edi, [ebp+NTFS.cur_index_buf]
1982         mov     dword[edi], 'INDX'
1983         mov     byte [edi+updateSequenceOffset], 28h
1984         mov     [edi+updateSequenceSize], al
1985         add     edi, recordNode
1986         shl     eax, 1
1987         add     eax, 28h-recordNode+7
1988         and     eax, not 7
1989         mov     [edi+indexOffset], eax
1990         mov     ecx, [esi+indexRecordSize]
1991         sub     ecx, recordNode
1992         mov     [edi+nodeAllocatedSize], ecx
1993         add     esi, rootNode
1994         push    esi
1995         mov     ecx, [esi+nodeRealSize]
1996         sub     ecx, [esi+indexOffset]
1997         add     eax, ecx
1998         mov     [edi+nodeRealSize], eax
1999         mov     eax, [esi+nonLeafFlag]
2000         mov     [edi+nonLeafFlag], eax
2001         shr     ecx, 2
2002         add     esi, [esi+indexOffset]
2003         add     edi, [edi+indexOffset]
2004         rep movsd       ; copy root indexes
2005 ; clear root node
2006         mov     cl, 10
2007         mov     edi, [esp]
2008         xor     eax, eax
2009         rep stosd
2010         pop     edi
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]
2018         add     edi, 28h
2019         mov     eax, edi
2020         sub     eax, esi
2021         mov     word [esi+sizeWithoutHeader], 38h
2022         xchg    [esi+sizeWithHeader], eax
2023         add     esi, eax
2024         mov     [ebp+NTFS.attr_offs], edi
2025         cmp     byte [esi], 0xA0
2026         jnz     @f
2027         cmp     dword [esi+attributeAllocatedSize], 0
2028         jz      @f
2029         mov     eax, [ebp+NTFS.frs_buffer]
2030         mov     ecx, eax
2031         add     ecx, [eax+recordRealSize]
2032         sub     ecx, esi
2033         shr     ecx, 2
2034         rep movsd
2035         sub     edi, eax
2036         mov     [eax+recordRealSize], edi
2037         call    .ntfsNodeAlloc
2038         jc      ntfsErrorPop3
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]
2043         mov     [edi-8], eax
2044         jmp     .refresh
2047         mov     cl, 32
2048         xor     eax, eax
2049         rep stosd
2050         mov     eax, [ebp+NTFS.cur_subnode_size]
2051         cmp     eax, [ebp+NTFS.cur_size]
2052         jnz     @f
2053         cmp     [ebp+NTFS.sectors_per_cluster], 1
2054         jz      @f
2055         mov     al, 1
2057         mov     [ebp+NTFS.fileDataSize], eax
2058         mov     edi, [ebp+NTFS.BitmapStart]
2059         call    ntfsSpaceAlloc
2060         movi    eax, ERROR_DISK_FULL
2061         jc      ntfsErrorPop3
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]
2071         dec     eax
2072         mov     [edi+lastVCN], eax
2073         inc     eax
2074         mul     [ebp+NTFS.sectors_per_cluster]
2075         shl     eax, 9
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
2081         push    edi
2082         mov     esi, edi
2083         add     edi, 48h
2084         call    createMcbEntry
2085         mov     esi, [ebp+NTFS.frs_buffer]
2086         pop     edi
2087         mov     al, [esi+newAttributeID]
2088         mov     [edi+attributeID], al
2089         add     edi, 50h
2090         inc     eax
2091 ; create $Bitmap
2092         mov     [edi+attributeID], al
2093         inc     eax
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
2105         add     edi, 30h
2106         sub     edi, esi
2107         mov     [esi+recordRealSize], edi
2108         mov     eax, [ebp+NTFS.fileDataStart]
2109         mul     [ebp+NTFS.sectors_per_cluster]
2110         mov     edx, eax
2111         jmp     @f
2113 .refresh:
2114         mov     [ebp+NTFS.cur_size], 0
2115         call    ntfs_read_attr.continue
2116         movi    eax, ERROR_FS_FAIL
2117         jc      ntfsErrorPop3
2118         mov     edx, [ebp+NTFS.LastRead]
2120         mov     ebx, [ebp+NTFS.cur_index_buf]
2121         call    writeRecord
2122         mov     ebx, [ebp+NTFS.frs_buffer]
2123         mov     edx, [ebp+NTFS.rootLastRead]
2124         call    writeRecord
2125         mov     esi, [esp+4]
2126         call    ntfs_find_lfn.doit2
2127         test    eax, eax
2128         jz      .errorPop3
2129         mov     edi, [ebp+NTFS.cur_index_buf]
2130         mov     edx, [esp]
2131 .indexRecord:
2132         add     edi, recordNode
2133         add     edx, [edi+nodeRealSize]
2134         cmp     [edi+nodeAllocatedSize], edx
2135         jc      .arborizeTree
2136         mov     [edi+nodeRealSize], edx
2137         jmp     .common
2139 .errorPop3:
2140         add     esp, 12
2141         jmp     ntfsUnsupported
2143 .ntfsNodeAlloc:
2144 ; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
2145 ;   out:
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
2152         jnz     .ret
2153         movzx   ecx, word [esi+sizeWithoutHeader]
2154         shr     ecx, 2
2155         movzx   edi, byte [esi+attributeOffset]
2156         add     edi, esi
2157         mov     edx, edi
2158         or      eax, -1
2159         repz scasd
2160         jnz     @f
2161         cmp     [edi], eax
2162         jnz     .ret
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]
2168         add     eax, 8
2169         cmp     [esi+recordAllocatedSize], eax
2170         jc      .ret
2171         mov     [esi+recordRealSize], eax
2172         xor     eax, eax
2173         stosd
2174         mov     [edi], eax
2175         mov     [edi+8], eax
2176         dec     eax
2177         mov     [edi+4], eax
2179         sub     edi, 4
2180         mov     eax, [edi]
2181         not     eax
2182         bsf     eax, eax
2183         bts     [edi], eax
2184         sub     edi, edx
2185         shl     edi, 3
2186         add     eax, edi
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]
2191         jz      @f
2192         mul     [ebp+NTFS.sectors_per_cluster]
2194         mov     [ebp+NTFS.cur_offs], eax
2195         add     eax, ecx
2196         shl     eax, 9
2197         mov     esi, [ebp+NTFS.attr_offs]
2198         cmp     [esi+attributeAllocatedSize], eax
2199         jnc     @f
2200         xor     edx, edx
2201         jmp     resizeAttribute
2203 .ret:
2204         movi    eax, ERROR_UNSUPPORTED_FS
2205         stc
2207         ret
2209 .arborizeTree:      ; find median index
2210         mov     ecx, [edi+nodeRealSize]
2211         sub     ecx, [edi+indexOffset]
2212         shr     ecx, 1
2213         add     edi, [edi+indexOffset]
2214         xor     eax, eax
2216         add     edi, eax
2217         mov     ax, [edi+indexAllocatedSize]
2218         sub     ecx, eax
2219         jnc     @b
2220         add     eax, 8
2221         mov     esi, [ebp+NTFS.secondIndexBuffer]
2222         cmp     dword [esi], 'INDX'
2223         jz      @f
2224 ; move index to the root node
2225         mov     esi, [ebp+NTFS.frs_buffer]
2226         mov     ecx, eax
2227         add     ecx, 8
2228         add     ecx, [esi+recordRealSize]
2229         cmp     [esi+recordAllocatedSize], ecx
2230         jc      .growTree
2231         push    edi eax
2232         call    .ntfsNodeAlloc
2233         jc      ntfsErrorPop5
2234         pop     eax
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]
2240         add     ecx, edi
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]
2248         mov     edi, esi
2249         sub     esi, eax
2250         neg     ecx
2251         add     ecx, esi
2252         shr     ecx, 2
2253         sub     esi, 4
2254         sub     edi, 4
2255         std
2256         rep movsd   ; make space
2257         mov     [edi], ecx
2258         mov     edi, esi
2259         add     edi, 4
2260         mov     esi, [esp]
2261         add     word [esi+indexAllocatedSize], 8
2262         mov     byte [esi+indexFlags], 1
2263         mov     ecx, eax
2264         sub     ecx, 8
2265         shr     ecx, 2
2266         cld
2267         rep movsd   ; insert index
2268         mov     eax, [ebp+NTFS.newRecord]
2269         stosd
2270         jmp     .splitNode
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
2277         add     edi, recordNode
2278         mov     eax, [edi+indexOffset]
2279         add     eax, 18h
2280         mov     [edi+nodeRealSize], eax
2281         add     edi, [edi+indexOffset]
2282         mov     ecx, 6
2283         xor     eax, eax
2284         mov     [ebp+NTFS.indexPointer], edi
2285         push    edi
2286         rep stosd
2287         pop     edi
2288         mov     eax, [ebp+NTFS.newRecord]
2289         mov     byte [edi+indexAllocatedSize], 18h
2290         mov     byte [edi+indexFlags], 3
2291         mov     [edi+16], eax
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
2300         jc      ntfsErrorPop5
2301         pop     eax edi
2302 @@:         ; move index to the branch node
2303         push    edi eax
2304         call    .ntfsNodeAlloc
2305         jc      ntfsErrorPop5
2306         mov     eax, [esp]
2307         mov     esi, [ebp+NTFS.secondIndexBuffer]
2308         add     esi, recordNode
2309         mov     ecx, [esi+nodeRealSize]
2310         add     eax, ecx
2311         cmp     [esi+nodeAllocatedSize], eax
2312         jc      .growBranch
2313         mov     [esi+nodeRealSize], eax
2314         lea     edi, [esi+eax-4]
2315         add     esi, ecx
2316         mov     ecx, esi
2317         sub     ecx, [ebp+NTFS.indexPointer]
2318         shr     ecx, 2
2319         sub     esi, 4
2320         std
2321         rep movsd   ; make space
2322         mov     [edi], ecx
2323         pop     ecx
2324         sub     ecx, 8
2325         shr     ecx, 2
2326         mov     edi, esi
2327         add     edi, 4
2328         mov     esi, [esp]
2329         add     word [esi+indexAllocatedSize], 8
2330         mov     byte [esi+indexFlags], 1
2331         cld
2332         rep movsd   ; insert index
2333         mov     eax, [ebp+NTFS.newRecord]
2334         stosd
2335         mov     ebx, [ebp+NTFS.secondIndexBuffer]
2336         mov     edx, [ebp+NTFS.nodeLastRead]
2337         push    esi
2338         call    writeRecord
2339         pop     esi
2340 .splitNode:
2341         mov     edi, [ebp+NTFS.cur_index_buf]
2342         mov     eax, edi
2343         add     eax, recordNode
2344         add     eax, [edi+recordNode+nodeRealSize]
2345         sub     eax, esi
2346         push    eax
2347         mov     ecx, [edi+recordNode+indexOffset]
2348         add     eax, ecx
2349         add     ecx, recordNode
2350         shr     ecx, 2
2351         push    esi
2352         mov     esi, edi
2353         mov     edi, [ebp+NTFS.secondIndexBuffer]
2354         rep movsd
2355         pop     esi
2356         pop     ecx
2357         shr     ecx, 2
2358         rep movsd
2359         mov     edi, [ebp+NTFS.secondIndexBuffer]
2360         mov     [edi+recordNode+nodeRealSize], eax
2361         pop     edi
2362         mov     cl, 4
2363         xor     eax, eax
2364         mov     esi, edi
2365         rep stosd
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
2371         add     esi, recordNode
2372         sub     edi, esi
2373         mov     [esi+nodeRealSize], edi
2374         mov     ebx, [ebp+NTFS.secondIndexBuffer]
2375         mov     edx, [ebp+NTFS.LastRead]
2376         call    writeRecord
2377         jmp     .refresh
2379 .common:
2380         add     edi, edx
2381         sub     edi, 4
2382         mov     esi, edi
2383         sub     esi, [esp]
2384         mov     ecx, esi
2385         sub     ecx, eax    ; eax = pointer in the record
2386         shr     ecx, 2
2387         inc     ecx
2388         std
2389         rep movsd           ; move forward, make space
2390         mov     ecx, [esp]
2391         shr     ecx, 2
2392         xor     eax, eax
2393         rep stosd
2394         cld
2395         add     edi, 4
2396         call    ntfsGetTime
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
2405         pop     ecx
2406         pop     esi
2407         mov     [edi+indexAllocatedSize], cx    ; fill index with data
2408         mov     eax, [esp]
2409         shl     eax, 1
2410         add     eax, 42h
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]
2418         shr     eax, 8
2419         add     ecx, 30h+48h+8+18h+8
2420         add     ecx, eax
2421         mov     eax, [ebp+NTFS.fileRealSize]
2422         add     ecx, eax
2423         mov     [edi+fileRealSize], eax
2424         cmp     [ebp+NTFS.frs_size], ecx
2425         jc      @f
2426         xor     eax, eax
2428         mov     ecx, [ebp+NTFS.sectors_per_cluster]
2429         shl     ecx, 9
2430         add     eax, ecx
2431         dec     eax
2432         xor     edx, edx
2433         div     ecx
2434         mov     [ebp+NTFS.fileDataSize], eax
2435         mul     ecx
2436         mov     [edi+fileAllocatedSize], eax
2437         pop     ecx
2438         mov     [ebp+NTFS.indexPointer], edi
2439         mov     [edi+fileNameLength], cl
2440         add     edi, fileName
2441 @@:         ; record filename
2442         call    utf8to16
2443         stosw
2444         loop    @b
2445         mov     eax, [ebp+NTFS.LastRead]
2446         mov     [ebp+NTFS.nodeLastRead], eax
2447         cmp     [ebp+NTFS.bFolder], 0
2448         jz      @f
2449         mov     edi, [ebp+NTFS.indexPointer]
2450         bts     dword [edi+fileFlags], 28
2451         jmp     .mftBitmap
2453 @@: ; 3. File data
2454         cmp     [ebp+NTFS.fileDataSize], 0
2455         jz      .mftBitmap
2456         mov     edi, [ebp+NTFS.BitmapStart]
2457         call    ntfsSpaceAlloc
2458         jc      ntfsDiskFull
2459         mov     eax, [ebp+NTFS.fileDataStart]
2460         mul     [ebp+NTFS.sectors_per_cluster]
2461         mov     ecx, [ebp+NTFS.fileRealSize]
2462         add     ecx, 511
2463         shr     ecx, 9
2464         mov     ebx, [ebp+NTFS.fileDataBuffer]
2465         call    fs_write64_app
2466         test    eax, eax
2467         jnz     ntfsDevice
2468     ; 4. MFT record
2469 .mftBitmap: ; search for free record
2470         mov     edi, [ebp+NTFS.mftBitmapBuffer]
2471         mov     ecx, [ebp+NTFS.mftBitmapSize]
2472         mov     al, -1
2473         add     edi, 3
2474         sub     ecx, 3
2475         repz scasb
2476         dec     edi
2477         movzx   eax, byte [edi]
2478         not     al
2479         bsf     ecx, eax
2480         jz      .extendBitmapMFT    ; no free records
2481         bts     [edi], ecx
2482 ; get record location
2483         sub     edi, [ebp+NTFS.mftBitmapBuffer]
2484         shl     edi, 3
2485         add     edi, ecx
2486         mov     [ebp+NTFS.newRecord], edi
2487         mov     eax, [ebp+NTFS.frs_size]
2488         shr     eax, 9
2489         mul     edi
2490         mov     [ebp+NTFS.cur_iRecord], 0
2491         mov     [ebp+NTFS.cur_attr], 0x80
2492         mov     [ebp+NTFS.cur_offs], eax
2493         push    eax
2494         mov     [ebp+NTFS.cur_size], 0
2495         mov     eax, [ebp+NTFS.frs_buffer]
2496         mov     [ebp+NTFS.cur_buf], eax
2497         call    ntfs_read_attr
2498         pop     eax
2499         jc      ntfsFail
2500         cmp     eax, [ebp+NTFS.mftSize]
2501         jnc     .extendMFT
2502         jmp     .mftRecord
2504 .extendBitmapMFT:
2505         mov     eax, [ebp+NTFS.sectors_per_cluster]
2506         mov     [ebp+NTFS.cur_offs], eax
2507         shl     eax, 9
2508         cmp     [ebp+NTFS.mftBitmapSize], eax
2509         jnc     ntfsUnsupported
2510         mov     [ebp+NTFS.cur_iRecord], 0
2511         mov     [ebp+NTFS.cur_attr], 0xB0
2512         mov     [ebp+NTFS.cur_size], 0
2513         call    ntfs_read_attr
2514         jc      ntfsFail
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]
2521         add     edi, ecx
2522         mov     eax, ecx
2523         mov     edx, [ebp+NTFS.attr_offs]
2524         add     ecx, 8
2525         mov     [edx+attributeRealSize], ecx
2526         mov     [edx+initialDataSize], ecx
2527         shl     eax, 3
2528         mov     [ebp+NTFS.newRecord], eax
2529         mov     dword [edi], 1
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
2534         jc      ntfsFail
2535         mov     [ebp+NTFS.mftBitmapSize], ecx
2536 .extendMFT:
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]
2544         xor     ax, ax
2545         add     eax, 10000h
2546         adc     edx, 0
2547         push    [ebp+NTFS.fileDataStart]
2548         push    [ebp+NTFS.fileDataSize]
2549         call    resizeAttribute
2550         jc      ntfsErrorPop2
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]
2557         shr     ecx, 9
2558         call    fs_write64_sys  ; $MFTMirr
2559 ; update $MFT retrieval information
2560         mov     edi, [ebp+NTFS.mft_retrieval_end]
2561         mov     eax, [edi-4]
2562         add     eax, [edi-8]
2563         mov     edx, [ebp+NTFS.fileDataSize]
2564         cmp     eax, [ebp+NTFS.fileDataStart]
2565         jnz     .newFragment
2566         add     [edi-8], edx
2567         jmp     @f
2568 .newFragment:
2569         lea     eax, [ebp+NTFS.attrlist_buf]
2570         cmp     eax, edi
2571         jz      @f
2572         mov     [edi], edx
2573         mov     eax, [ebp+NTFS.fileDataStart]
2574         mov     [edi+4], eax
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
2580         call    ntfsSpaceClean
2581         pop     [ebp+NTFS.fileDataSize]
2582         pop     [ebp+NTFS.fileDataStart]
2583 .mftRecord:
2584         mov     ecx, [ebp+NTFS.frs_size]
2585         shr     ecx, 2
2586         mov     edi, [ebp+NTFS.frs_buffer]
2587         xor     eax, eax
2588         rep stosd
2589         mov     esi, [ebp+NTFS.indexPointer]
2590         mov     eax, [ebp+NTFS.newRecord]
2591         mov     [esi+fileRecordReference], eax
2592         rdtsc
2593         mov     [esi+fileReferenceReuse], ax
2594         mov     edi, [ebp+NTFS.frs_buffer]
2595 ; record header
2596         mov     [edi+reuseCounter], ax
2597         mov     [edi+2ah], ax
2598         mov     eax, [ebp+NTFS.frs_size]
2599         mov     [edi+recordAllocatedSize], eax
2600         shr     eax, 9
2601         inc     eax
2602         mov     [edi+updateSequenceSize], al
2603         shl     eax, 1
2604         add     eax, 2ah+7
2605         and     eax, not 7
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
2611         add     edi, eax
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
2617         mov     cl, 8
2618         add     esi, fileCreated
2619         add     edi, 18h
2620         rep movsd
2621         add     edi, 16
2622         mov     esi, [ebp+NTFS.indexPointer]
2623 ; $FileName
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]
2631         add     ecx, 8
2632         mov     [edi+sizeWithHeader], ecx
2633         add     edi, 18h
2634         add     esi, 16
2635         sub     ecx, 18h
2636         shr     ecx, 2
2637         rep movsd
2638         mov     byte [edi+sizeWithHeader], 50h
2639         mov     byte [edi+attributeID], 2
2640         cmp     [ebp+NTFS.bFolder], 1
2641         jz      .indexRoot
2642 ; $Data
2643         mov     byte [edi+attributeType], 80h
2644         mov     eax, [ebp+NTFS.fileDataSize]
2645         test    eax, eax
2646         jz      .resident
2647         mov     esi, [ebp+NTFS.indexPointer]
2648         dec     eax
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
2657         push    edi
2658         mov     esi, edi
2659         add     edi, 40h
2660         call    createMcbEntry
2661         inc     edi
2662         jmp     @f
2664 .resident:
2665         mov     ecx, [ebp+NTFS.fileRealSize]
2666         mov     [edi+sizeWithoutHeader], ecx
2667         mov     byte [edi+attributeOffset], 18h
2668         push    edi
2669         mov     esi, [ebp+NTFS.fileDataBuffer]
2670         add     edi, 18h
2671         rep movsb
2673         mov     eax, edi
2674         pop     edi
2675         sub     eax, edi
2676         add     eax, 7
2677         and     eax, not 7
2678         mov     [edi+sizeWithHeader], eax
2679         add     edi, eax
2680         mov     al, 1
2681         jmp     .end
2683 .indexRoot:
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]
2694         mov     dl, 1
2695         shl     eax, 8
2697         shl     eax, 1
2698         shl     edx, 1
2699         cmp     eax, [ebp+NTFS.frs_size]
2700         jc      @b
2701         shr     edx, 1
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
2709         add     edi, 50h
2710         mov     al, 3
2711 .end:
2712         mov     ebx, [ebp+NTFS.frs_buffer]
2713         mov     dword [edi], -1
2714         mov     dword [edi+4], 0
2715         add     edi, 8
2716         sub     edi, ebx
2717         mov     [ebx+recordFlags], al
2718         mov     [ebx+recordRealSize], edi
2719         mov     edx, [ebp+NTFS.LastRead]
2720         call    writeRecord
2721 ; write MFT bitmap
2722         mov     eax, [ebp+NTFS.newRecord]
2723         shr     eax, 3+9
2724         mov     ebx, eax
2725         shl     ebx, 9
2726         add     eax, [ebp+NTFS.mftBitmapLocation]
2727         add     ebx, [ebp+NTFS.mftBitmapBuffer]
2728         mov     ecx, 1
2729         xor     edx, edx
2730         call    fs_write64_sys
2731 ; 5. Write directory node
2732         mov     ebx, [ebp+NTFS.cur_index_buf]
2733         mov     edx, [ebp+NTFS.nodeLastRead]
2734         call    writeRecord
2735         mov     ebx, [ebp+NTFS.fileRealSize]
2736 ntfsDone:
2737         mov     esi, [ebp+PARTITION.Disk]
2738         call    disk_sync
2739         call    ntfs_unlock
2740         xor     eax, eax
2741         ret
2743 writeRecord:
2744 ; make updateSequence and write to disk
2745 ;   in:
2746 ; ebx -> record
2747 ; edx = partition sector
2748         mov     esi, ebx
2749         mov     edi, ebx
2750         movzx   ecx, word [esi+updateSequenceOffset]
2751         add     edi, ecx
2752         mov     ax, [edi]
2753         inc     ax
2754         stosw
2755         mov     cx, [esi+updateSequenceSize]
2756         dec     ecx
2757         push    ecx
2759         add     esi, 510
2760         movsw
2761         mov     [esi-2], ax
2762         loop    @b
2763         mov     eax, edx
2764         xor     edx, edx
2765         pop     ecx
2766         jmp     fs_write64_sys
2768 createMcbEntry:
2769 ;   in:
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]
2775         xor     edx, edx
2776         shl     eax, 1
2777         jnc     @f
2778         not     eax
2780         inc     edx
2781         shr     eax, 8
2782         jnz     @b
2783         mov     eax, [ebp+NTFS.fileDataSize]
2784         shl     eax, 1
2785         xor     ecx, ecx
2787         inc     ecx
2788         shr     eax, 8
2789         jnz     @b
2790         lea     eax, [edi+edx+1]
2791         add     eax, ecx
2792         sub     eax, esi
2793         sub     eax, [esi+sizeWithHeader]
2794         jc      @f
2795         add     word [esi+sizeWithHeader], 8    ; extend attribute
2796         mov     esi, [ebp+NTFS.frs_buffer]
2797         mov     eax, [esi+recordRealSize]
2798         add     eax, 8
2799         cmp     [esi+recordAllocatedSize], eax
2800         jc      .end    ; no space in the record
2801         mov     [esi+recordRealSize], eax
2802         push    ecx edi
2803         add     esi, eax
2804         mov     ecx, esi
2805         sub     ecx, edi
2806         sub     ecx, 8
2807         shr     ecx, 2
2808         mov     edi, esi
2809         sub     edi, 4
2810         sub     esi, 12
2811         std
2812         rep movsd
2813         cld
2814         pop     edi ecx
2816         mov     eax, edx
2817         shl     eax, 4
2818         add     eax, ecx
2819         stosb
2820         lea     esi, [ebp+NTFS.fileDataSize]
2821         rep movsb
2822         lea     esi, [ebp+NTFS.fileDataStart]
2823         mov     ecx, edx
2824         rep movsb
2825         mov     [edi], cl
2826 .end:
2827         ret
2829 resizeAttribute:
2830 ;   in:
2831 ; [ebp+NTFS.frs_buffer] -> file record
2832 ; [ebp+NTFS.attr_offs] -> attribute
2833 ; edx:eax = new size
2834 ;   out:
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
2842         jz      .resident
2843         mov     ecx, [ebp+NTFS.sectors_per_cluster]
2844         shl     ecx, 9
2845         mov     [esi+attributeRealSize], eax
2846         mov     [esi+attributeRealSize+4], edx
2847         mov     [esi+initialDataSize], eax
2848         mov     [esi+initialDataSize+4], edx
2849         sub     eax, 1
2850         sbb     edx, 0
2851         jc      .makeResident
2852         div     ecx
2853         mov     edi, eax
2854         inc     eax
2855         mul     ecx
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]
2861         sub     edi, ecx
2862         mov     [ebp+NTFS.fileDataSize], edi
2863         jz      .done
2864         jc      .shrinkAttribute
2865 ; extend attribute
2866         xor     edi, edi
2867         add     esi, eax
2868         push    edi edi edi edi
2870         mov     edx, eax
2871         mov     eax, esi
2872         add     edi, [esp+8]
2873         call    ntfs_decode_mcb_entry
2874         jc      @b
2875         mov     [esp+4], edx
2876         mov     [esp+12], edi
2877         add     edi, [esp]
2878         push    edi
2879         shr     edi, 5
2880         shl     edi, 2
2881         push    eax
2882         cmp     edi, [ebp+NTFS.BitmapStart]
2883         jnc     @f
2884         cmp     [ebp+NTFS.cur_iRecord], 0
2885         jz      @f
2886         mov     edi, [ebp+NTFS.BitmapStart]
2888         call    ntfsSpaceAlloc
2889         jc      .err1
2890         mov     eax, [ebp+NTFS.fileDataStart]
2891         pop     edi
2892         pop     edx
2893         cmp     edx, eax
2894         jnz     .newEntry
2895         pop     edx
2896         pop     edi
2897         pop     [ebp+NTFS.fileDataStart]
2898         mov     [esp], eax
2899         push    [ebp+NTFS.fileDataSize]
2900         add     [ebp+NTFS.fileDataSize], edx
2901         jmp     @f
2903 .newEntry:
2904         add     esp, 12
2905         pop     edx
2906         push    eax
2907         push    [ebp+NTFS.fileDataSize]
2908         sub     eax, edx
2909         mov     [ebp+NTFS.fileDataStart], eax
2911         mov     esi, [ebp+NTFS.attr_offs]
2912         call    createMcbEntry
2913         pop     [ebp+NTFS.fileDataSize]
2914         pop     [ebp+NTFS.fileDataStart]
2915         movi    eax, ERROR_UNSUPPORTED_FS
2916 .done:
2917         ret
2919 .err1:
2920         add     esp, 24
2921         stc
2922 .err2:
2923         movi    eax, ERROR_DISK_FULL
2924         ret
2926 .err3:
2927         movi    eax, ERROR_FS_FAIL
2928         add     esp, 20
2929         stc
2930         ret
2932 .shrinkAttribute:
2933         add     ecx, edi
2934         inc     ecx
2935         add     esi, eax
2936         xor     edi, edi
2937         sub     esp, 20
2939         mov     [esp+16], esi
2940         call    ntfs_decode_mcb_entry
2941         jnc     .err3
2942         add     edi, [esp+8]
2943         sub     ecx, [esp]
2944         jnc     @b
2945         mov     ebx, ecx
2946         add     ecx, [esp]
2947         mov     eax, [esp+8]
2948         mov     [ebp+NTFS.fileDataSize], ecx
2949         mov     [ebp+NTFS.fileDataStart], eax
2950         push    edi
2951         add     edi, ecx
2952         neg     ebx
2953         call    ntfsSpaceFree
2954         pop     edi
2955         jc      .end
2957         call    ntfs_decode_mcb_entry
2958         jnc     .end
2959         cmp     dword[esp+8], 0
2960         jz      @b
2961         add     edi, [esp+8]
2962         mov     ebx, [esp]
2963         call    ntfsSpaceFree
2964         jnc     @b
2965 .end:
2966         add     esp, 16
2967         pop     edi
2968         cmp     [ebp+NTFS.fileDataSize], 0
2969         jz      @f
2970         mov     esi, [ebp+NTFS.attr_offs]
2971         call    createMcbEntry
2972         mov     [ebp+NTFS.fileDataSize], 0
2974         ret
2976 .resident:
2977         test    edx, edx
2978         jnz     .nonResident
2979         cmp     eax, 8000h
2980         jnc     .nonResident
2981         add     ax, [esi+attributeOffset]
2982         sub     eax, [esi+sizeWithHeader]
2983         jc      @f
2984         mov     edi, [ebp+NTFS.frs_buffer]
2985         mov     ecx, eax
2986         add     ecx, [edi+recordRealSize]
2987         cmp     [edi+recordAllocatedSize], ecx
2988         jc      .nonResident
2989         add     eax, 7
2990         and     eax, not 7
2991         add     [edi+recordRealSize], eax
2992         add     edi, [edi+recordRealSize]
2993         add     [esi+sizeWithHeader], eax
2994         add     esi, [esi+sizeWithHeader]
2995         mov     ecx, edi
2996         sub     ecx, esi
2997         shr     ecx, 2
2998         sub     edi, 4
2999         mov     esi, edi
3000         sub     esi, eax
3001         std
3002         rep movsd
3003         mov     ecx, eax
3004         shr     ecx, 2
3005         xor     eax, eax
3006         rep stosd
3007         cld
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
3013         clc
3014         ret
3016 .nonResident:   ; convert resident to non-resident
3017         mov     eax, dword [ebp+NTFS.attr_size]
3018         sub     eax, 1
3019         sbb     edx, 0
3020         mov     ecx, [ebp+NTFS.sectors_per_cluster]
3021         shl     ecx, 9
3022         div     ecx
3023         inc     eax
3024         mov     [ebp+NTFS.fileDataSize], eax
3025         mov     edi, [ebp+NTFS.BitmapStart]
3026         push    ecx
3027         call    ntfsSpaceAlloc
3028         pop     ecx
3029         jc      .err2
3030         mov     esi, [ebp+NTFS.attr_offs]
3031         xor     eax, eax
3032         xor     edx, edx
3034         add     eax, ecx
3035         inc     edx
3036         cmp     eax, [esi+sizeWithoutHeader]
3037         jc      @b
3038         push    edx
3039         push    eax
3040         stdcall kernel_alloc, eax
3041         mov     ecx, [esp]
3042         shr     ecx, 2
3043         mov     edi, eax
3044         mov     ebx, eax
3045         xor     eax, eax
3046         rep stosd
3047         mov     al, [esi+attributeOffset]
3048         mov     ecx, [esi+sizeWithoutHeader]
3049         add     esi, eax
3050         mov     edi, ebx
3051         rep movsb
3052         mov     eax, [ebp+NTFS.fileDataStart]
3053         mul     [ebp+NTFS.sectors_per_cluster]
3054         pop     ecx
3055         shr     ecx, 9
3056         call    fs_write64_app
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]
3062         sub     ecx, esi
3063         shr     ecx, 2
3064         lea     edi, [ebp+NTFS.bitmap_buf]
3065         push    ecx
3066         rep movsd
3067         mov     edi, [ebp+NTFS.attr_offs]
3068         add     edi, 16
3069         mov     cl, 6
3070         xor     eax, eax
3071         rep stosd
3072         mov     edi, [ebp+NTFS.attr_offs]
3073         mov     eax, [ebp+NTFS.fileDataSize]
3074         dec     eax
3075         mov     [edi+lastVCN], eax
3076         inc     eax
3077         mov     ecx, [ebp+NTFS.sectors_per_cluster]
3078         shl     ecx, 9
3079         mul     ecx
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
3091         mov     esi, edi
3092         add     edi, 40h
3093         call    createMcbEntry
3094         mov     eax, edi
3095         mov     edi, [ebp+NTFS.attr_offs]
3096         sub     eax, edi
3097         add     eax, 8
3098         and     eax, not 7
3099         mov     [edi+sizeWithHeader], eax
3100         pop     ecx
3101         lea     esi, [ebp+NTFS.bitmap_buf]
3102         add     edi, eax
3103         rep movsd
3104         mov     esi, [ebp+NTFS.frs_buffer]
3105         sub     edi, esi
3106         mov     [esi+recordRealSize], edi
3107         pop     edx
3108         sub     [ebp+NTFS.fileDataSize], edx
3109         add     [ebp+NTFS.fileDataStart], edx
3110         ret
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
3117         add     esi, eax
3118         xor     edi, edi
3119         sub     esp, 16
3121         call    ntfs_decode_mcb_entry
3122         jnc     @f
3123         cmp     dword[esp+8], 0
3124         jz      @b
3125         add     edi, [esp+8]
3126         mov     ebx, [esp]
3127         call    ntfsSpaceFree
3128         jnc     @b
3130         add     esp, 16
3131         mov     [ebp+NTFS.fileDataSize], 0
3132         ret
3134 ntfsSpaceClean:
3135 ; clean up to 16 Mb of disk space
3136 ;   in:
3137 ; [ebp+NTFS.fileDataStart] = block to clean
3138 ; [ebp+NTFS.fileDataSize] = block size
3139         mov     eax, [ebp+NTFS.fileDataSize]
3140         test    eax, eax
3141         jz      @f
3142         mul     [ebp+NTFS.sectors_per_cluster]
3143         cmp     eax, 8001h
3144         jnc     @f
3145         push    eax
3146         shl     eax, 9
3147         stdcall kernel_alloc, eax
3148         pop     ecx
3149         test    eax, eax
3150         jz      @f
3151         push    ecx
3152         shl     ecx, 7
3153         mov     edi, eax
3154         mov     ebx, eax
3155         xor     eax, eax
3156         rep stosd
3157         mov     eax, [ebp+NTFS.fileDataStart]
3158         mul     [ebp+NTFS.sectors_per_cluster]
3159         mov     [ebp+NTFS.LastRead], eax
3160         pop     ecx
3161         call    fs_write64_app
3162         stdcall kernel_free, ebx
3164         ret
3166 ntfsSpaceAlloc:
3167 ; allocate disk space
3168 ;   in:
3169 ; edi = offset in bitmap to start search from
3170 ; [ebp+NTFS.fileDataSize] = block size in clusters
3171 ;   out:
3172 ; [ebp+NTFS.fileDataStart] = allocated block starting cluster
3173 ; CF=1 -> disk full
3174         mov     ecx, [ebp+NTFS.BitmapBuffer]
3175         add     edi, ecx
3176         add     ecx, [ebp+NTFS.BitmapSize]
3177         sub     ecx, edi
3178         ja      @f
3179         push    eax
3180         call    bitmapBuffering
3181         pop     eax
3182         shl     ecx, 2
3184         shr     ecx, 2
3185         push    ecx
3186         mov     eax, [ebp+NTFS.fileDataSize]
3187         shr     eax, 5
3188         jz      .small
3189         mov     ebx, eax    ; bitmap dwords
3190 .start:
3191         mov     ecx, [ebp+NTFS.BitmapBuffer]
3192         add     ecx, [ebp+NTFS.BitmapSize]
3193         sub     ecx, edi
3194         shr     ecx, 2
3196         xor     eax, eax
3197         repnz scasd         ; search for empty dword
3198         jz      @f
3199         call    bitmapBuffering
3200         jmp     @b
3202         cmp     ecx, ebx
3203         jnc     @f
3204         call    bitmapBuffering
3205         jmp     @b
3207         sub     edi, 4
3208         mov     ecx, ebx
3209         mov     esi, edi
3210         xor     eax, eax
3211         repz scasd          ; check following dwords
3212         jnz     .start
3213         sub     esi, 4
3214         mov     eax, [esi]
3215         xor     edx, edx
3216         bsr     edx, eax
3217         inc     edx
3218         push    edx         ; starting bit
3219         push    esi         ; starting dword
3220         add     esi, 4
3221         neg     edx
3222         add     edx, 32
3223         mov     eax, [ebp+NTFS.fileDataSize]
3224         sub     eax, edx
3225         mov     edx, eax
3226         shr     eax, 5
3227         shl     eax, 2
3228         add     esi, eax
3229         mov     eax, [esi]
3230         bsf     ecx, eax    ; check last dword
3231         jz      .done
3232         and     edx, 31
3233         cmp     ecx, edx
3234         jnc     .done
3235         add     esp, 8
3236         jmp     .start
3239         sub     edi, 4
3240         call    bitmapBuffering
3241         push    ecx
3242 .small:     ; less than 32 clusters
3243         pop     ecx
3244         or      eax, -1
3245         repz scasd
3246         jecxz   @b
3247         push    ecx
3248         mov     eax, [edi-4]
3249         not     eax
3251         bsf     ecx, eax    ; first 0
3252         jz      .small
3253         not     eax
3254         shr     eax, cl
3255         shl     eax, cl
3256         bsf     edx, eax    ; next 1
3257         jz      @f
3258         sub     edx, ecx
3259         cmp     edx, [ebp+NTFS.fileDataSize]
3260         jnc     .got        ; fits inside
3261         bsf     ecx, eax
3262         not     eax
3263         shr     eax, cl
3264         shl     eax, cl
3265         jmp     @b
3267 @@:         ; next dword
3268         mov     eax, [edi]
3269         bsf     edx, eax
3270         jz      .got        ; empty
3271         add     edx, 32
3272         sub     edx, ecx
3273         cmp     edx, [ebp+NTFS.fileDataSize]
3274         jc      .small
3275 .got:
3276         sub     edi, 4
3277         push    ecx         ; starting bit
3278         push    edi         ; starting dword
3279 .done:      ; mark space
3280         pop     edi ecx
3281         cmp     ecx, 32
3282         jc      @f
3283         xor     ecx, ecx
3284         add     edi, 4
3286         push    ecx edi
3287         or      eax, -1
3288         shr     eax, cl
3289         shl     eax, cl
3290         neg     ecx
3291         add     ecx, 32
3292         sub     ecx, [ebp+NTFS.fileDataSize]
3293         jc      @f
3294         shl     eax, cl     ; fits inside dword
3295         shr     eax, cl
3296         or      [edi], eax
3297         jmp     .end
3300         or      [edi], eax
3301         neg     ecx
3302         push    ecx
3303         shr     ecx, 5
3304         add     edi, 4
3305         or      eax, -1
3306         rep stosd
3307         pop     ecx
3308         and     ecx, 31
3309         shr     eax, cl
3310         shl     eax, cl
3311         not     eax
3312         or      [edi], eax
3313 .end:
3314         pop     eax
3315         pop     ecx
3316         sub     eax, [ebp+NTFS.BitmapBuffer]
3317         shl     eax, 3
3318         add     eax, ecx
3319         pop     ecx
3320         mov     ecx, [ebp+NTFS.fileDataSize]
3321         mov     [ebp+NTFS.fileDataStart], eax
3322         add     ecx, eax
3323         add     ecx, 4095
3324         shr     ecx, 3+9
3325         shr     eax, 3+9
3326         sub     ecx, eax
3327         mov     ebx, eax
3328         shl     ebx, 9
3329         add     eax, [ebp+NTFS.BitmapLocation]
3330         add     ebx, [ebp+NTFS.BitmapBuffer]
3331         xor     edx, edx
3332         jmp     fs_write64_app
3334 ntfsSpaceFree:
3335 ; free disk space
3336 ;   in:
3337 ; edi = starting cluster
3338 ; ebx = size in clusters
3339         mov     eax, edi
3340         add     eax, ebx
3341         shr     eax, 3
3342         cmp     eax, [ebp+NTFS.BitmapSize]
3343         jc      @f
3344         add     eax, [ebp+NTFS.BitmapBuffer]
3345         push    edi
3346         mov     edi, eax
3347         call    bitmapBuffering
3348         pop     edi
3350         push    edi
3351         mov     ecx, edi
3352         shr     edi, 5
3353         shl     edi, 2
3354         add     edi, [ebp+NTFS.BitmapBuffer]
3355         and     ecx, 31
3356         xor     eax, eax
3357         dec     eax
3358         shr     eax, cl
3359         shl     eax, cl
3360         neg     ecx
3361         add     ecx, 32
3362         sub     ecx, ebx
3363         jc      @f
3364         shl     eax, cl     ; fits inside dword
3365         shr     eax, cl
3366         not     eax
3367         and     [edi], eax
3368         jmp     .writeBitmap
3371         not     eax
3372         and     [edi], eax
3373         neg     ecx
3374         push    ecx
3375         shr     ecx, 5
3376         add     edi, 4
3377         xor     eax, eax
3378         rep stosd
3379         pop     ecx
3380         and     ecx, 31
3381         dec     eax
3382         shr     eax, cl
3383         shl     eax, cl
3384         and     [edi], eax
3385 .writeBitmap:
3386         pop     eax
3387         mov     edi, eax
3388         lea     ecx, [eax+ebx+4095]
3389         shr     eax, 3+9
3390         shr     ecx, 3+9
3391         sub     ecx, eax
3392         mov     ebx, eax
3393         shl     ebx, 9
3394         add     eax, [ebp+NTFS.BitmapLocation]
3395         add     ebx, [ebp+NTFS.BitmapBuffer]
3396         xor     edx, edx
3397         jmp     fs_write64_app
3399 bitmapBuffering:
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
3404         push    ebx
3405         mov     eax, [ebp+NTFS.BitmapTotalSize]
3406         cmp     eax, [ebp+NTFS.BitmapSize]
3407         jz      .end
3408         stdcall alloc_pages, 8
3409         test    eax, eax
3410         jz      .end
3411         add     eax, 3
3412         mov     ebx, [ebp+NTFS.BitmapBuffer]
3413         add     ebx, [ebp+NTFS.BitmapSize]
3414         push    ebx
3415         mov     ecx, 8
3416         call    commit_pages
3417         mov     eax, [ebp+NTFS.BitmapSize]
3418         shr     eax, 9
3419         add     eax, [ebp+NTFS.BitmapLocation]
3420         pop     ebx
3421         mov     ecx, 64
3422         xor     edx, edx
3423         call    fs_read64_app
3424         test    eax, eax
3425         jnz     .err
3426         mov     eax, [ebp+NTFS.BitmapSize]
3427         add     eax, 8000h
3428         cmp     [ebp+NTFS.BitmapTotalSize], eax
3429         jnc     @f
3430         mov     eax, [ebp+NTFS.BitmapTotalSize]
3432         mov     [ebp+NTFS.BitmapSize], eax
3433         pop     ebx
3434         mov     ecx, [ebp+NTFS.BitmapBuffer]
3435         add     ecx, eax
3436         sub     ecx, edi
3437         jbe     bitmapBuffering
3438         shr     ecx, 2
3439         ret
3441 .err:
3442         mov     eax, [ebp+NTFS.BitmapBuffer]
3443         add     eax, [ebp+NTFS.BitmapSize]
3444         mov     ecx, 8
3445         call    release_pages
3446 .end:
3447         add     esp, 12     ; ret
3448         stc
3449         ret
3451 ;----------------------------------------------------------------
3452 ntfs_WriteFile:
3453         call    ntfs_lock
3454         call    ntfs_find_lfn
3455         jc      ntfsNotFound
3456         cmp     [ebp+NTFS.cur_iRecord], 16
3457         jc      ntfsDenied
3458         test    dword [eax+fileFlags], 10000001h
3459         jnz     ntfsDenied
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'
3465         jz      @f
3466         mov     esi, [ebp+NTFS.frs_buffer]
3467         mov     ecx, [esi+recordRealSize]
3468         shr     ecx, 2
3469         rep movsd
3470         mov     esi, [ebp+NTFS.attr_offs]
3471         mov     cl, [esi+attributeOffset]
3472         sub     esi, [ebp+NTFS.frs_buffer]
3473         add     eax, ecx
3474         add     eax, esi
3476         mov     edi, eax
3477         mov     eax, [ebx+4]
3478         mov     edx, [ebx+8]
3479         add     eax, [ebx+12]
3480         adc     edx, 0
3482         cmp     edx, [edi+fileRealSize+4]
3483         jc      @f
3484         jnz     .resize
3485         cmp     [edi+fileRealSize], eax
3486         jnc     @f
3487 .resize:
3488         mov     [edi+fileRealSize], eax
3489         mov     [edi+fileRealSize+4], edx
3491         push    edx eax ebx
3492         call    ntfsGetTime
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
3499         pop     ebx ecx 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
3505         call    ntfs_read_attr
3506         jc      ntfsFail
3507         mov     esi, edi
3508         mov     edi, [ebp+NTFS.frs_buffer]
3509         cmp     word [edi+baseRecordReuse], 0
3510         jnz     ntfsUnsupported     ; auxiliary record
3511         mov     al, [edi+attributeOffset]
3512         add     edi, eax
3513         mov     al, [edi+attributeOffset]
3514         add     edi, eax
3515         mov     eax, ecx
3516         mov     ecx, 6
3517         add     esi, fileModified
3518         add     edi, 8
3519         rep movsd
3520         mov     ecx, [ebp+NTFS.attr_offs]
3521         cmp     word [ecx+attributeFlags], 0
3522         jnz     ntfsUnsupported
3523         push    ebx
3524         cmp     byte [ecx+nonResidentFlag], 0
3525         jz      .resizeAttribute
3526         cmp     edx, [ecx+attributeRealSize+4]
3527         jc      .writeNode
3528         jnz     .resizeAttribute
3529         cmp     [ecx+attributeRealSize], eax
3530         jnc     .writeNode
3531 .resizeAttribute:
3532         call    resizeAttribute
3533         jc      ntfsErrorPop
3534         mov     ecx, [ebp+NTFS.attr_offs]
3535         cmp     byte [ecx+nonResidentFlag], 1
3536         jz      @f
3537         mov     ebx, [esp]
3538         movzx   edi, byte [ecx+attributeOffset]
3539         add     edi, ecx
3540         add     edi, [ebx+4]
3541         mov     ecx, [ebx+12]
3542         mov     esi, [ebx+16]
3543         rep movsb
3545         mov     ebx, [ebp+NTFS.frs_buffer]
3546         mov     edx, [ebp+NTFS.mftLastRead]
3547         call    writeRecord     ; file
3548         call    ntfs_restore_usa_frs
3549 .writeNode:
3550         mov     ebx, [ebp+NTFS.cur_index_buf]
3551         mov     edx, [ebp+NTFS.nodeLastRead]
3552         call    writeRecord     ; directory
3553         pop     ebx
3554         mov     ecx, [ebp+NTFS.attr_offs]
3555         cmp     byte [ecx+nonResidentFlag], 0
3556         jz      .done
3557         mov     ecx, [ebx+12]
3558         test    ecx, ecx
3559         jz      .done
3560         mov     eax, [ebx+4]
3561         mov     edx, [ebx+8]
3562         mov     esi, [ebx+16]
3563         shrd    eax, edx, 9
3564         test    dword[ebx+4], 1FFh
3565         jz      .aligned
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
3571         jc      ntfsDevice
3572         mov     eax, [ebx+4]
3573         and     eax, 1FFh
3574         add     edi, eax
3575         sub     eax, [ebp+NTFS.cur_read]
3576         neg     eax
3577         push    ecx
3578         cmp     ecx, eax
3579         jb      @f
3580         mov     ecx, eax
3582         sub     [esp], ecx
3583         rep movsb
3584         push    ebx
3585         mov     eax, [ebp+NTFS.LastRead]
3586         lea     ebx, [ebp+NTFS.bitmap_buf]
3587         mov     ecx, 1
3588         xor     edx, edx
3589         call    fs_write64_app
3590         pop     ebx
3591         pop     ecx
3592         test    ecx, ecx
3593         jz      .done
3594         mov     eax, [ebx+4]
3595         mov     edx, [ebx+8]
3596         shrd    eax, edx, 9
3597         inc     eax
3598 .aligned:
3599         push    ecx
3600         shr     ecx, 9
3601         mov     [ebp+NTFS.cur_offs], eax
3602         mov     [ebp+NTFS.cur_size], ecx
3603         mov     [ebp+NTFS.cur_buf], esi
3604         add     eax, ecx
3605         push    eax
3606         mov     [ebp+NTFS.bWriteAttr], 1
3607         call    ntfs_read_attr.continue
3608         mov     [ebp+NTFS.bWriteAttr], 0
3609         pop     [ebp+NTFS.cur_offs]
3610         pop     ecx
3611         jc      ntfsDevice
3612         and     ecx, 1FFh
3613         jz      .done
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
3619         jc      ntfsDevice
3620         rep movsb
3621         push    ebx
3622         mov     eax, [ebp+NTFS.LastRead]
3623         lea     ebx, [ebp+NTFS.bitmap_buf]
3624         mov     ecx, 1
3625         xor     edx, edx
3626         call    fs_write64_app
3627         pop     ebx
3628 .done:
3629         mov     ebx, [ebx+12]
3630         jmp     ntfsDone
3632 ;----------------------------------------------------------------
3633 ntfs_Delete:
3634         call    ntfs_lock
3635         call    ntfs_find_lfn
3636         jc      ntfsNotFound
3637         cmp     [ebp+NTFS.cur_iRecord], 16
3638         jc      ntfsDenied
3639         test    byte [eax+fileFlags], 1
3640         jnz     ntfsDenied
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]
3648         shr     eax, 3
3649         cmp     eax, [ebp+NTFS.mftBitmapSize]
3650         jnc     ntfsUnsupported
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
3655         call    ntfs_read_attr
3656         jnc     @f
3657         xor     eax, eax
3658         push    ebx eax eax eax eax
3659         mov     [esp+12], esp
3660         push    eax
3661         mov     ebx, esp
3662         mov     [ebp+NTFS.cur_attr], 0x90   ; folder?
3663         call    ntfs_ReadFolder.doit
3664         mov     edx, [esp+12]
3665         add     esp, 20
3666         pop     ebx
3667         test    eax, eax
3668         jnz     .ret
3669         cmp     edx, 2
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
3685         jnc     ntfsUnsupported
3686         mov     esi, [ebp+NTFS.attr_offs]
3687         cmp     byte [esi+nonResidentFlag], 0
3688         jz      .deleteFileRecord
3689         movzx   eax, byte [esi+dataRunsOffset]
3690         add     esi, eax
3691         xor     edi, edi
3692         sub     esp, 16
3694         call    ntfs_decode_mcb_entry
3695         jnc     @f
3696         cmp     dword[esp+8], 0
3697         jz      @b
3698         add     edi, [esp+8]
3699         mov     ebx, [esp]
3700         call    ntfsSpaceFree
3701         jnc     @b
3703         add     esp, 16
3704 .deleteFileRecord:
3705         mov     ebx, [ebp+NTFS.frs_buffer]
3706         mov     byte [ebx+recordFlags], 0
3707         mov     edx, [ebp+NTFS.mftLastRead]
3708         call    writeRecord
3709 .writeBitmapMFT:
3710         mov     eax, [ebp+NTFS.cur_iRecord]
3711         mov     ecx, eax
3712         shr     eax, 3
3713         and     ecx, 7
3714         mov     edi, [ebp+NTFS.mftBitmapBuffer]
3715         btr     [edi+eax], ecx
3716         shr     eax, 9
3717         mov     ebx, eax
3718         shl     ebx, 9
3719         add     eax, [ebp+NTFS.mftBitmapLocation]
3720         add     ebx, edi
3721         mov     ecx, 1
3722         xor     edx, edx
3723         call    fs_write64_sys
3724 .backToIndex:
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
3729         jc      ntfsFail
3730         mov     ebx, [ebp+NTFS.secondIndexBuffer]
3731         mov     byte [ebx], 0
3732         mov     ebx, [ebp+NTFS.LastRead]
3733         mov     [ebp+NTFS.nodeLastRead], ebx
3734         xor     ebx, ebx
3735         test    byte [eax+indexFlags], 1
3736         jz      .deleteIndex    ; no subnode
3737         mov     edi, eax
3738         call    .findSubindex
3739         jc      ntfsFail
3740         movzx   edx, word [edi+indexAllocatedSize]
3741         test    esi, esi
3742         jz      @f
3743         sub     edx, eax
3744         sub     edx, 8
3746         mov     eax, edi
3747         mov     ebx, esi
3748         jmp     @f
3750 .deleteIndex:
3751         movzx   edx, word [eax+indexAllocatedSize]
3752         mov     ecx, [eax+fileRecordReference]
3753         cmp     [eax+edx+fileRecordReference], ecx
3754         jnz     @f
3755         add     dx, [eax+edx+indexAllocatedSize]
3757         mov     edi, [ebp+NTFS.cur_index_buf]
3758         cmp     dword [edi], 'INDX'
3759         jz      .indexRecord
3760         sub     eax, edi
3761         mov     edi, [ebp+NTFS.indexRoot]
3762         sub     [edi+sizeWithHeader], edx
3763         sub     [edi+sizeWithoutHeader], edx
3764         movzx   ecx, byte [edi+attributeOffset]
3765         add     edi, ecx
3766         add     eax, edi
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
3773         jmp     @f
3775 .indexRecord:
3776         add     edi, recordNode
3777         sub     [edi+nodeRealSize], edx
3778         mov     ecx, [edi+nodeRealSize]
3779         cmp     [edi+nodeAllocatedSize], ecx
3781         jc      ntfsUnsupported
3782         add     ecx, edi
3783         sub     ecx, eax
3784         mov     esi, eax
3785         add     esi, edx
3786         mov     edi, eax
3787         test    edx, edx
3788         jns     @f
3789         neg     edx
3790         add     edx, ecx
3791         sub     edx, 4
3792         add     esi, edx
3793         add     edi, edx
3794         std
3796         jz      @f
3797         shr     ecx, 2
3798         rep movsd
3799         cld
3801         test    ebx, ebx
3802         jz      .done
3803 ; copy index from the subnode to replace deleted pointing index
3804         movzx   ecx, word [ebx+indexAllocatedSize]
3805         mov     edx, ecx
3806         test    byte [ebx+indexFlags], 1
3807         jz      @f
3808         sub     ecx, 8
3809         movzx   edi, word [ebx+edx+indexAllocatedSize]
3810         add     edi, edx
3811         mov     esi, [ebx+ecx]
3812         mov     [ebx+edi-8], esi
3813         mov     [ebx+indexAllocatedSize], cx
3815         shr     ecx, 2
3816         mov     esi, ebx
3817         mov     edi, eax
3818         rep movsd
3819         add     word [eax+indexAllocatedSize], 8
3820         mov     byte [eax+indexFlags], 1
3821         mov     edi, [ebp+NTFS.secondIndexBuffer]
3822         mov     eax, ebx
3823         xor     ebx, ebx
3824         jmp     .indexRecord
3826 .done:
3827         mov     ebx, [ebp+NTFS.frs_buffer]
3828         mov     edx, [ebp+NTFS.rootLastRead]
3829         call    writeRecord
3830         mov     ebx, [ebp+NTFS.cur_index_buf]
3831         cmp     dword [ebx], 'INDX'
3832         jnz     @f
3833         mov     edx, [ebp+NTFS.nodeLastRead]
3834         call    writeRecord
3836         mov     ebx, [ebp+NTFS.secondIndexBuffer]
3837         cmp     byte [ebx], 0
3838         jz      ntfsDone
3839         mov     edx, [ebp+NTFS.LastRead]
3840         call    writeRecord
3841         jmp     ntfsDone
3843 .findSubindex:
3844 ; in: eax -> index
3845 ;   out:
3846 ; CF=1 -> error
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]
3853         push    edx
3854         cmp     edx, [ebp+NTFS.cur_subnode_size]
3855         jz      @f
3856         mul     [ebp+NTFS.sectors_per_cluster]
3858         mov     [ebp+NTFS.cur_attr], 0xA0
3859         mov     [ebp+NTFS.cur_offs], eax
3860         push    eax
3861         mov     ebx, [ebp+NTFS.secondIndexBuffer]
3862         mov     esi, ebx
3863         mov     [ebp+NTFS.cur_buf], ebx
3864         call    ntfs_read_attr.newAttribute
3865         pop     [ebp+NTFS.cur_offs]
3866         pop     eax
3867         jc      .ret
3868         cmp     dword [esi], 'INDX'
3869         stc
3870         jnz     .ret
3871         mov     [ebp+NTFS.cur_size], eax
3872         shl     eax, 9
3873         call    ntfs_restore_usa
3874         jc      .ret
3875         add     esi, recordNode
3876         add     esi, [esi+indexOffset]
3877         test    byte [esi+indexFlags], 2
3878         jnz     .emptyNode
3879         cmp     [ebp+NTFS.fragmentCount], 1
3880         stc
3881         jnz     .ret    ; record fragmented
3882         xor     eax, eax
3884         add     esi, eax
3885         mov     ax, [esi+indexAllocatedSize]
3886         test    byte [esi+eax+indexFlags], 2
3887         jz      @b
3888         test    byte [esi+indexFlags], 1
3889         jz      .ret
3890         add     eax, esi
3891         push    esi
3892         push    [ebp+NTFS.cur_offs]
3893         call    .findSubindex
3894         pop     [ebp+NTFS.cur_offs]
3895         pop     edx
3896         jc      .ret
3897         test    esi, esi
3898         jnz     .ret
3899         mov     esi, edx
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
3904         pop     eax
3905         jc      .ret
3906         shl     eax, 9
3907         call    ntfs_restore_usa
3908         jc      .ret
3909         movzx   eax, word [esi+indexAllocatedSize]
3910         sub     eax, 8
3911 .ret:
3912         ret
3914 .emptyNode:
3915         test    byte [esi+indexFlags], 1
3916         jz      @f
3917         mov     eax, esi
3918         push    [ebp+NTFS.cur_offs]
3919         call    .findSubindex
3920         pop     [ebp+NTFS.cur_offs]
3921         jc      .ret
3922         test    esi, esi
3923         jnz     .ret
3924 @@:         ; delete node
3925         mov     esi, [ebp+NTFS.attr_offs]
3926         add     esi, [esi+sizeWithHeader]
3927         cmp     byte [esi], 0xB0
3928         stc
3929         jnz     .ret
3930         movzx   eax, byte [esi+attributeOffset]
3931         add     esi, eax
3932         mov     eax, [ebp+NTFS.cur_offs]
3933         xor     edx, edx
3934         div     [ebp+NTFS.cur_size]
3935         mov     edx, eax
3936         shr     eax, 3
3937         and     edx, 7
3938         btr     [esi+eax], edx
3939         mov     esi, [ebp+NTFS.secondIndexBuffer]
3940         mov     byte [esi], 0
3941         xor     esi, esi
3942         ret
3944 ;----------------------------------------------------------------
3945 ntfs_SetFileEnd:
3946         call    ntfs_lock
3947         call    ntfs_find_lfn
3948         jc      ntfsNotFound
3949         cmp     [ebp+NTFS.cur_iRecord], 16
3950         jc      ntfsDenied
3951         test    dword [eax+fileFlags], 10000001h
3952         jnz     ntfsDenied
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'
3958         jz      @f
3959         mov     esi, [ebp+NTFS.frs_buffer]
3960         mov     ecx, [esi+recordRealSize]
3961         shr     ecx, 2
3962         rep movsd
3963         mov     esi, [ebp+NTFS.attr_offs]
3964         mov     cl, [esi+attributeOffset]
3965         sub     esi, [ebp+NTFS.frs_buffer]
3966         add     eax, ecx
3967         add     eax, esi
3969         mov     edi, eax
3970         mov     eax, [ebx+4]
3971         mov     edx, [ebx+8]
3972         mov     [edi+fileRealSize], eax
3973         mov     [edi+fileRealSize+4], edx
3974         push    edx eax ebx
3975         call    ntfsGetTime
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
3982         pop     ebx ecx 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
3988         call    ntfs_read_attr
3989         jc      ntfsFail
3990         mov     esi, edi
3991         mov     edi, [ebp+NTFS.frs_buffer]
3992         cmp     word [edi+baseRecordReuse], 0
3993         jnz     ntfsUnsupported     ; auxiliary record
3994         mov     al, [edi+attributeOffset]
3995         add     edi, eax
3996         mov     al, [edi+attributeOffset]
3997         add     edi, eax
3998         mov     eax, ecx
3999         mov     ecx, 6
4000         add     esi, fileModified
4001         add     edi, 8
4002         rep movsd
4003         mov     ecx, [ebp+NTFS.attr_offs]
4004         cmp     word [ecx+attributeFlags], 0
4005         jnz     ntfsUnsupported
4006         cmp     byte [ecx+nonResidentFlag], 0
4007         jz      .resizeAttribute
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
4015         shl     ecx, 9
4016         div     ecx
4017         test    edx, edx
4018         jz      .aligned
4019         push    edx
4020         push    ecx
4021         mul     [ebp+NTFS.sectors_per_cluster]
4022         mov     [ebp+NTFS.cur_offs], eax
4023         stdcall kernel_alloc, ecx
4024         pop     ecx
4025         pop     edi
4026         mov     esi, eax
4027         sub     ecx, edi
4028         add     edi, eax
4029         mov     [ebp+NTFS.cur_buf], eax
4030         call    ntfs_read_attr.continue
4031         jc      @f
4032         xor     eax, eax
4033         rep stosb
4034         push    ebx
4035         mov     eax, [ebp+NTFS.LastRead]
4036         mov     ebx, esi
4037         mov     ecx, [ebp+NTFS.sectors_per_cluster]
4038         xor     edx, edx
4039         call    fs_write64_app
4040         pop     ebx
4042         stdcall kernel_free, esi
4043 .aligned:
4044         mov     eax, [ebx+4]
4045         mov     edx, [ebx+8]
4046 .resizeAttribute:
4047         call    resizeAttribute
4048         jc      ntfsError
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
4055         call    ntfsSpaceClean
4056         jmp     ntfsDone
4058 ntfsGetTime:
4059         call    fsGetTime
4060         jmp     @f
4062 ntfsCalculateTime:
4063 ; in: esi -> data block
4064 ; out: edx:eax = seconds since 01.01.1601 x10000000
4065         call    fsCalculateTime
4067         mov     edx, 10000000
4068         mul     edx
4069         add     eax, 3365781504
4070         adc     edx, 29389701
4071         ret
4073 ;----------------------------------------------------------------
4074 ntfs_SetFileInfo:
4075         call    ntfs_lock
4076         call    ntfs_find_lfn
4077         jnc     @f
4078         test    eax, eax
4079         jz      ntfsFail
4080         jmp     ntfsNotFound
4083         cmp     [ebp+NTFS.fragmentCount], 1
4084         jnz     ntfsUnsupported     ; record fragmented
4085         mov     esi, [ebp+NTFS.cur_index_buf]
4086         cmp     dword [esi], 'INDX'
4087         jz      @f
4088         sub     eax, esi
4089         mov     esi, [ebp+NTFS.indexRoot]
4090         movzx   edx, byte [esi+attributeOffset]
4091         add     eax, esi
4092         add     eax, edx
4094         mov     esi, [ebx+16]
4095         mov     edi, eax
4096         mov     eax, [esi]
4097         and     eax, 27h
4098         and     byte [edi+fileFlags], -28h
4099         or      [edi+fileFlags], al
4100         add     esi, 8
4101         call    ntfsCalculateTime
4102         mov     [edi+fileCreated], eax
4103         mov     [edi+fileCreated+4], edx
4104         add     esi, 8
4105         call    ntfsCalculateTime
4106         mov     [edi+fileAccessed], eax
4107         mov     [edi+fileAccessed+4], edx
4108         add     esi, 8
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'
4114         jz      @f
4115         mov     ebx, [ebp+NTFS.frs_buffer]
4117         mov     edx, [ebp+NTFS.LastRead]
4118         call    writeRecord
4119         jmp     ntfsDone
4121 ntfsUnsupported:
4122         push    ERROR_UNSUPPORTED_FS
4123         jmp     ntfsOut
4124 ntfsDevice:
4125         push    ERROR_DEVICE
4126         jmp     ntfsOut
4127 ntfsNotFound:
4128         push    ERROR_FILE_NOT_FOUND
4129         jmp     ntfsOut
4130 ntfsDenied:
4131         push    ERROR_ACCESS_DENIED
4132         jmp     ntfsOut
4133 ntfsFail:
4134         push    ERROR_FS_FAIL
4135         jmp     ntfsOut
4136 ntfsDiskFull:
4137         push    ERROR_DISK_FULL
4138         jmp     ntfsOut
4139 ntfsErrorPop5:
4140         pop     ebx
4141         pop     ebx
4142 ntfsErrorPop3:
4143         pop     ebx
4144 ntfsErrorPop2:
4145         pop     ebx
4146 ntfsErrorPop:
4147         pop     ebx
4148 ntfsError:
4149         push    eax
4150 ntfsOut:
4151         call    ntfs_unlock
4152         xor     ebx, ebx
4153         pop     eax
4154         ret