a77e7ee15d
git-svn-id: svn://kolibrios.org@3598 a494cfbc-eb01-0410-851d-a64ba20cac60
1823 lines
48 KiB
PHP
1823 lines
48 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
$Revision$
|
|
|
|
|
|
ntfs_test_bootsec:
|
|
; in: ebx->buffer, edx=size of partition
|
|
; out: CF set <=> invalid
|
|
; 1. Name=='NTFS '
|
|
cmp dword [ebx+3], 'NTFS'
|
|
jnz .no
|
|
cmp dword [ebx+7], ' '
|
|
jnz .no
|
|
; 2. Number of bytes per sector is the same as for physical device
|
|
; (that is, 0x200 for hard disk)
|
|
cmp word [ebx+11], 0x200
|
|
jnz .no
|
|
; 3. Number of sectors per cluster must be power of 2
|
|
movzx eax, byte [ebx+13]
|
|
dec eax
|
|
js .no
|
|
test al, [ebx+13]
|
|
jnz .no
|
|
; 4. FAT parameters must be zero
|
|
cmp word [ebx+14], 0
|
|
jnz .no
|
|
cmp dword [ebx+16], 0
|
|
jnz .no
|
|
cmp byte [ebx+20], 0
|
|
jnz .no
|
|
cmp word [ebx+22], 0
|
|
jnz .no
|
|
cmp dword [ebx+32], 0
|
|
jnz .no
|
|
; 5. Number of sectors <= partition size
|
|
cmp dword [ebx+0x2C], 0
|
|
ja .no
|
|
cmp [ebx+0x28], edx
|
|
ja .no
|
|
; 6. $MFT and $MFTMirr clusters must be within partition
|
|
cmp dword [ebx+0x34], 0
|
|
ja .no
|
|
push edx
|
|
movzx eax, byte [ebx+13]
|
|
mul dword [ebx+0x30]
|
|
test edx, edx
|
|
pop edx
|
|
jnz .no
|
|
cmp eax, edx
|
|
ja .no
|
|
cmp dword [ebx+0x3C], 0
|
|
ja .no
|
|
push edx
|
|
movzx eax, byte [ebx+13]
|
|
mul dword [ebx+0x38]
|
|
test edx, edx
|
|
pop edx
|
|
jnz .no
|
|
cmp eax, edx
|
|
ja .no
|
|
; 7. Clusters per FRS must be either negative and in [-31,-9] or positive and power of 2
|
|
movsx eax, byte [ebx+0x40]
|
|
cmp al, -31
|
|
jl .no
|
|
cmp al, -9
|
|
jle @f
|
|
dec eax
|
|
js .no
|
|
test [ebx+0x40], al
|
|
jnz .no
|
|
@@:
|
|
; 8. Same for clusters per IndexAllocationBuffer
|
|
movsx eax, byte [ebx+0x44]
|
|
cmp al, -31
|
|
jl .no
|
|
cmp al, -9
|
|
jle @f
|
|
dec eax
|
|
js .no
|
|
test [ebx+0x44], al
|
|
jnz .no
|
|
@@:
|
|
; OK, this is correct NTFS bootsector
|
|
clc
|
|
ret
|
|
.no:
|
|
; No, this bootsector isn't NTFS
|
|
stc
|
|
ret
|
|
|
|
ntfs_setup: ; CODE XREF: part_set.inc
|
|
; By given bootsector, initialize some NTFS variables
|
|
; call ntfs_test_bootsec ; checking boot sector was already
|
|
; jc problem_fat_dec_count
|
|
movzx eax, byte [ebx+13]
|
|
mov [ntfs_data.sectors_per_cluster], eax
|
|
mov eax, [ebx+0x28]
|
|
add eax, [PARTITION_START]
|
|
dec eax
|
|
mov [PARTITION_END], eax
|
|
mov [fs_type], 1
|
|
mov eax, [ebx+0x30]
|
|
mov [ntfs_data.mft_cluster], eax
|
|
mov eax, [ebx+0x38]
|
|
mov [ntfs_data.mftmirr_cluster], eax
|
|
movsx eax, byte [ebx+0x40]
|
|
test eax, eax
|
|
js .1
|
|
mul [ntfs_data.sectors_per_cluster]
|
|
shl eax, 9
|
|
jmp .2
|
|
.1:
|
|
neg eax
|
|
mov ecx, eax
|
|
mov eax, 1
|
|
shl eax, cl
|
|
.2:
|
|
mov [ntfs_data.frs_size], eax
|
|
movsx eax, byte [ebx+0x44]
|
|
test eax, eax
|
|
js .3
|
|
mul [ntfs_data.sectors_per_cluster]
|
|
shl eax, 9
|
|
jmp .4
|
|
.3:
|
|
neg eax
|
|
mov ecx, eax
|
|
mov eax, 1
|
|
shl eax, cl
|
|
.4:
|
|
mov [ntfs_data.iab_size], eax
|
|
; allocate space for buffers
|
|
add eax, [ntfs_data.frs_size]
|
|
push eax
|
|
call kernel_alloc
|
|
test eax, eax
|
|
jz problem_fat_dec_count
|
|
mov [ntfs_data.frs_buffer], eax
|
|
add eax, [ntfs_data.frs_size]
|
|
mov [ntfs_data.iab_buffer], eax
|
|
; read $MFT disposition
|
|
mov eax, [ntfs_data.mft_cluster]
|
|
mul [ntfs_data.sectors_per_cluster]
|
|
call ntfs_read_frs_sector
|
|
cmp [hd_error], 0
|
|
jnz .usemirr
|
|
cmp dword [ebx], 'FILE'
|
|
jnz .usemirr
|
|
call ntfs_restore_usa_frs
|
|
jnc .mftok
|
|
.usemirr:
|
|
and [hd_error], 0
|
|
mov eax, [ntfs_data.mftmirr_cluster]
|
|
mul [ntfs_data.sectors_per_cluster]
|
|
call ntfs_read_frs_sector
|
|
cmp [hd_error], 0
|
|
jnz @f
|
|
cmp dword [ebx], 'FILE'
|
|
jnz @f
|
|
call ntfs_restore_usa_frs
|
|
jnc .mftok
|
|
@@:
|
|
; $MFT and $MFTMirr invalid!
|
|
.fail_free_frs:
|
|
push [ntfs_data.frs_buffer]
|
|
call kernel_free
|
|
jmp problem_fat_dec_count
|
|
.fail_free_mft:
|
|
push [ntfs_data.mft_retrieval]
|
|
call kernel_free
|
|
jmp .fail_free_frs
|
|
.mftok:
|
|
; read $MFT table retrieval information
|
|
; start with one page, increase if not enough (when MFT too fragmented)
|
|
push ebx
|
|
push 0x1000
|
|
call kernel_alloc
|
|
pop ebx
|
|
test eax, eax
|
|
jz .fail_free_frs
|
|
mov [ntfs_data.mft_retrieval], eax
|
|
and [ntfs_data.mft_retrieval_size], 0
|
|
mov [ntfs_data.mft_retrieval_alloc], 0x1000/8
|
|
; $MFT base record must contain unnamed non-resident $DATA attribute
|
|
movzx eax, word [ebx+14h]
|
|
add eax, ebx
|
|
.scandata:
|
|
cmp dword [eax], -1
|
|
jz .fail_free_mft
|
|
cmp dword [eax], 0x80
|
|
jnz @f
|
|
cmp byte [eax+9], 0
|
|
jz .founddata
|
|
@@:
|
|
add eax, [eax+4]
|
|
jmp .scandata
|
|
.founddata:
|
|
cmp byte [eax+8], 0
|
|
jz .fail_free_mft
|
|
; load first portion of $DATA attribute retrieval information
|
|
mov edx, [eax+0x18]
|
|
mov [ntfs_data.mft_retrieval_end], edx
|
|
mov esi, eax
|
|
movzx eax, word [eax+0x20]
|
|
add esi, eax
|
|
sub esp, 10h
|
|
.scanmcb:
|
|
call ntfs_decode_mcb_entry
|
|
jnc .scanmcbend
|
|
call .get_mft_retrieval_ptr
|
|
mov edx, [esp] ; block length
|
|
mov [eax], edx
|
|
mov edx, [esp+8] ; block addr (relative)
|
|
mov [eax+4], edx
|
|
inc [ntfs_data.mft_retrieval_size]
|
|
jmp .scanmcb
|
|
.scanmcbend:
|
|
add esp, 10h
|
|
; there may be other portions of $DATA attribute in auxiliary records;
|
|
; if they will be needed, they will be loaded later
|
|
|
|
mov [ntfs_data.cur_index_size], 0x1000/0x200
|
|
push 0x1000
|
|
call kernel_alloc
|
|
test eax, eax
|
|
jz .fail_free_mft
|
|
mov [ntfs_data.cur_index_buf], eax
|
|
|
|
popad
|
|
call free_hd_channel
|
|
and [hd1_status], 0
|
|
ret
|
|
|
|
.get_mft_retrieval_ptr:
|
|
pushad
|
|
mov eax, [ntfs_data.mft_retrieval_size]
|
|
cmp eax, [ntfs_data.mft_retrieval_alloc]
|
|
jnz .ok
|
|
add eax, 0x1000/8
|
|
mov [ntfs_data.mft_retrieval_alloc], eax
|
|
shl eax, 3
|
|
push eax
|
|
call kernel_alloc
|
|
test eax, eax
|
|
jnz @f
|
|
popad
|
|
add esp, 14h
|
|
jmp .fail_free_mft
|
|
@@:
|
|
mov esi, [ntfs_data.mft_retrieval]
|
|
mov edi, eax
|
|
mov ecx, [ntfs_data.mft_retrieval_size]
|
|
add ecx, ecx
|
|
rep movsd
|
|
push [ntfs_data.mft_retrieval]
|
|
mov [ntfs_data.mft_retrieval], eax
|
|
call kernel_free
|
|
mov eax, [ntfs_data.mft_retrieval_size]
|
|
.ok:
|
|
shl eax, 3
|
|
add eax, [ntfs_data.mft_retrieval]
|
|
mov [esp+28], eax
|
|
popad
|
|
ret
|
|
|
|
ntfs_read_frs_sector:
|
|
push eax ecx
|
|
add eax, [PARTITION_START]
|
|
mov ecx, [ntfs_data.frs_size]
|
|
shr ecx, 9
|
|
mov ebx, [ntfs_data.frs_buffer]
|
|
push ebx
|
|
@@:
|
|
call hd_read
|
|
cmp [hd_error], 0
|
|
jnz .fail
|
|
add ebx, 0x200
|
|
inc eax
|
|
loop @b
|
|
.fail:
|
|
pop ebx
|
|
pop ecx eax
|
|
ret
|
|
|
|
uglobal
|
|
align 4
|
|
ntfs_cur_attr dd ?
|
|
ntfs_cur_iRecord dd ?
|
|
ntfs_cur_offs dd ? ; in sectors
|
|
ntfs_cur_size dd ? ; in sectors
|
|
ntfs_cur_buf dd ?
|
|
ntfs_cur_read dd ? ; [output]
|
|
ntfs_bCanContinue db ?
|
|
rb 3
|
|
|
|
ntfs_attrlist_buf rb 0x400
|
|
ntfs_attrlist_mft_buf rb 0x400
|
|
ntfs_bitmap_buf rb 0x400
|
|
|
|
ntfs_attr_iRecord dd ?
|
|
ntfs_attr_iBaseRecord dd ?
|
|
ntfs_attr_offs dd ?
|
|
ntfs_attr_list dd ?
|
|
ntfs_attr_size dq ?
|
|
ntfs_cur_tail dd ?
|
|
endg
|
|
|
|
ntfs_read_attr:
|
|
; in: global variables
|
|
; out: [ntfs_cur_read]
|
|
pushad
|
|
and [ntfs_cur_read], 0
|
|
cmp [ntfs_cur_iRecord], 0
|
|
jnz .nomft
|
|
cmp [ntfs_cur_attr], 0x80
|
|
jnz .nomft
|
|
mov eax, [ntfs_data.mft_retrieval_end]
|
|
inc eax
|
|
mul [ntfs_data.sectors_per_cluster]
|
|
cmp eax, [ntfs_cur_offs]
|
|
jbe .nomft
|
|
; precalculated part of $Mft $DATA
|
|
mov esi, [ntfs_data.mft_retrieval]
|
|
mov eax, [ntfs_cur_offs]
|
|
xor edx, edx
|
|
div [ntfs_data.sectors_per_cluster]
|
|
; eax = VCN, edx = offset in sectors from beginning of cluster
|
|
xor ecx, ecx ; ecx will contain LCN
|
|
.mftscan:
|
|
add ecx, [esi+4]
|
|
sub eax, [esi]
|
|
jb @f
|
|
add esi, 8
|
|
push eax
|
|
mov eax, [ntfs_data.mft_retrieval_end]
|
|
shl eax, 3
|
|
add eax, [ntfs_data.mft_retrieval]
|
|
cmp eax, esi
|
|
pop eax
|
|
jnz .mftscan
|
|
jmp .nomft
|
|
@@:
|
|
push ecx
|
|
add ecx, eax
|
|
add ecx, [esi]
|
|
push eax
|
|
push edx
|
|
mov eax, [ntfs_data.sectors_per_cluster]
|
|
mul ecx
|
|
; eax = sector on partition
|
|
add eax, [PARTITION_START]
|
|
pop edx
|
|
add eax, edx
|
|
mov ebx, [ntfs_cur_buf]
|
|
pop ecx
|
|
neg ecx
|
|
imul ecx, [ntfs_data.sectors_per_cluster]
|
|
sub ecx, edx
|
|
cmp ecx, [ntfs_cur_size]
|
|
jb @f
|
|
mov ecx, [ntfs_cur_size]
|
|
@@:
|
|
; ecx = number of sequential sectors to read
|
|
call hd_read
|
|
cmp [hd_error], 0
|
|
jnz .errread
|
|
add [ntfs_cur_read], 0x200
|
|
dec [ntfs_cur_size]
|
|
inc [ntfs_cur_offs]
|
|
add ebx, 0x200
|
|
mov [ntfs_cur_buf], ebx
|
|
inc eax
|
|
loop @b
|
|
pop ecx
|
|
xor eax, eax
|
|
xor edx, edx
|
|
cmp [ntfs_cur_size], eax
|
|
jz @f
|
|
add esi, 8
|
|
push eax
|
|
mov eax, [ntfs_data.mft_retrieval_end]
|
|
shl eax, 3
|
|
add eax, [ntfs_data.mft_retrieval]
|
|
cmp eax, esi
|
|
pop eax
|
|
jz .nomft
|
|
jmp .mftscan
|
|
@@:
|
|
popad
|
|
ret
|
|
.errread:
|
|
pop ecx
|
|
.errret:
|
|
stc
|
|
popad
|
|
ret
|
|
.nomft:
|
|
; 1. Read file record.
|
|
; N.B. This will do recursive call of read_attr for $MFT::$Data.
|
|
mov eax, [ntfs_cur_iRecord]
|
|
mov [ntfs_attr_iRecord], eax
|
|
and [ntfs_attr_list], 0
|
|
or dword [ntfs_attr_size], -1
|
|
or dword [ntfs_attr_size+4], -1
|
|
or [ntfs_attr_iBaseRecord], -1
|
|
call ntfs_read_file_record
|
|
test eax, eax
|
|
jz .errret
|
|
; 2. Find required attribute.
|
|
mov eax, [ntfs_data.frs_buffer]
|
|
; a) For auxiliary records, read base record
|
|
; N.B. If base record is present,
|
|
; base iRecord may be 0 (for $Mft), but SequenceNumber is nonzero
|
|
cmp dword [eax+24h], 0
|
|
jz @f
|
|
mov eax, [eax+20h]
|
|
; test eax, eax
|
|
; jz @f
|
|
.beginfindattr:
|
|
mov [ntfs_attr_iRecord], eax
|
|
call ntfs_read_file_record
|
|
test eax, eax
|
|
jz .errret
|
|
@@:
|
|
; b) Scan for required attribute and for $ATTR_LIST
|
|
mov eax, [ntfs_data.frs_buffer]
|
|
movzx ecx, word [eax+14h]
|
|
add eax, ecx
|
|
mov ecx, [ntfs_cur_attr]
|
|
and [ntfs_attr_offs], 0
|
|
.scanattr:
|
|
cmp dword [eax], -1
|
|
jz .scandone
|
|
cmp dword [eax], ecx
|
|
jz .okattr
|
|
cmp [ntfs_attr_iBaseRecord], -1
|
|
jnz .scancont
|
|
cmp dword [eax], 0x20 ; $ATTR_LIST
|
|
jnz .scancont
|
|
mov [ntfs_attr_list], eax
|
|
jmp .scancont
|
|
.okattr:
|
|
; ignore named $DATA attributes (aka NTFS streams)
|
|
cmp ecx, 0x80
|
|
jnz @f
|
|
cmp byte [eax+9], 0
|
|
jnz .scancont
|
|
@@:
|
|
mov [ntfs_attr_offs], eax
|
|
.scancont:
|
|
add eax, [eax+4]
|
|
jmp .scanattr
|
|
.continue:
|
|
pushad
|
|
and [ntfs_cur_read], 0
|
|
.scandone:
|
|
; c) Check for required offset and length
|
|
mov ecx, [ntfs_attr_offs]
|
|
jecxz .noattr
|
|
push [ntfs_cur_size]
|
|
push [ntfs_cur_read]
|
|
call .doreadattr
|
|
pop edx
|
|
pop eax
|
|
jc @f
|
|
cmp [ntfs_bCanContinue], 0
|
|
jz @f
|
|
sub edx, [ntfs_cur_read]
|
|
neg edx
|
|
shr edx, 9
|
|
sub eax, edx
|
|
mov [ntfs_cur_size], eax
|
|
jnz .not_in_cur
|
|
@@:
|
|
popad
|
|
ret
|
|
.noattr:
|
|
.not_in_cur:
|
|
cmp [ntfs_cur_attr], 0x20
|
|
jz @f
|
|
mov ecx, [ntfs_attr_list]
|
|
test ecx, ecx
|
|
jnz .lookattr
|
|
.ret_is_attr:
|
|
cmp [ntfs_attr_offs], 1 ; CF set <=> ntfs_attr_offs == 0
|
|
popad
|
|
ret
|
|
.lookattr:
|
|
; required attribute or required offset was not found in base record;
|
|
; it may be present in auxiliary records;
|
|
; scan $ATTR_LIST
|
|
mov eax, [ntfs_attr_iBaseRecord]
|
|
cmp eax, -1
|
|
jz @f
|
|
call ntfs_read_file_record
|
|
test eax, eax
|
|
jz .errret
|
|
or [ntfs_attr_iBaseRecord], -1
|
|
@@:
|
|
push [ntfs_cur_offs]
|
|
push [ntfs_cur_size]
|
|
push [ntfs_cur_read]
|
|
push [ntfs_cur_buf]
|
|
push dword [ntfs_attr_size]
|
|
push dword [ntfs_attr_size+4]
|
|
or dword [ntfs_attr_size], -1
|
|
or dword [ntfs_attr_size+4], -1
|
|
and [ntfs_cur_offs], 0
|
|
mov [ntfs_cur_size], 2
|
|
and [ntfs_cur_read], 0
|
|
mov eax, ntfs_attrlist_buf
|
|
cmp [ntfs_cur_iRecord], 0
|
|
jnz @f
|
|
mov eax, ntfs_attrlist_mft_buf
|
|
@@:
|
|
mov [ntfs_cur_buf], eax
|
|
push eax
|
|
call .doreadattr
|
|
pop esi
|
|
mov edx, 1
|
|
pop dword [ntfs_attr_size+4]
|
|
pop dword [ntfs_attr_size]
|
|
mov ebp, [ntfs_cur_read]
|
|
pop [ntfs_cur_buf]
|
|
pop [ntfs_cur_read]
|
|
pop [ntfs_cur_size]
|
|
pop [ntfs_cur_offs]
|
|
jc .errret
|
|
or edi, -1
|
|
lea ebp, [ebp+esi-1Ah]
|
|
.scanliststart:
|
|
mov eax, [ntfs_cur_attr]
|
|
.scanlist:
|
|
cmp esi, ebp
|
|
jae .scanlistdone
|
|
cmp eax, [esi]
|
|
jz @f
|
|
.scanlistcont:
|
|
movzx ecx, word [esi+4]
|
|
add esi, ecx
|
|
jmp .scanlist
|
|
@@:
|
|
; ignore named $DATA attributes (aka NTFS streams)
|
|
cmp eax, 0x80
|
|
jnz @f
|
|
cmp byte [esi+6], 0
|
|
jnz .scanlistcont
|
|
@@:
|
|
push eax
|
|
mov eax, [esi+8]
|
|
test eax, eax
|
|
jnz .testf
|
|
mov eax, dword [ntfs_attr_size]
|
|
and eax, dword [ntfs_attr_size+4]
|
|
cmp eax, -1
|
|
jnz .testfz
|
|
; if attribute is in auxiliary records, its size is defined only in first
|
|
mov eax, [esi+10h]
|
|
call ntfs_read_file_record
|
|
test eax, eax
|
|
jnz @f
|
|
.errret_pop:
|
|
pop eax
|
|
jmp .errret
|
|
@@:
|
|
mov eax, [ntfs_data.frs_buffer]
|
|
movzx ecx, word [eax+14h]
|
|
add eax, ecx
|
|
mov ecx, [ntfs_cur_attr]
|
|
@@:
|
|
cmp dword [eax], -1
|
|
jz .errret_pop
|
|
cmp dword [eax], ecx
|
|
jz @f
|
|
.l1:
|
|
add eax, [eax+4]
|
|
jmp @b
|
|
@@:
|
|
cmp eax, 0x80
|
|
jnz @f
|
|
cmp byte [eax+9], 0
|
|
jnz .l1
|
|
@@:
|
|
cmp byte [eax+8], 0
|
|
jnz .sdnores
|
|
mov eax, [eax+10h]
|
|
mov dword [ntfs_attr_size], eax
|
|
and dword [ntfs_attr_size+4], 0
|
|
jmp .testfz
|
|
.sdnores:
|
|
mov ecx, [eax+30h]
|
|
mov dword [ntfs_attr_size], ecx
|
|
mov ecx, [eax+34h]
|
|
mov dword [ntfs_attr_size+4], ecx
|
|
.testfz:
|
|
xor eax, eax
|
|
.testf:
|
|
imul eax, [ntfs_data.sectors_per_cluster]
|
|
cmp eax, [ntfs_cur_offs]
|
|
pop eax
|
|
ja @f
|
|
mov edi, [esi+10h] ; keep previous iRecord
|
|
jmp .scanlistcont
|
|
@@:
|
|
.scanlistfound:
|
|
cmp edi, -1
|
|
jnz @f
|
|
popad
|
|
ret
|
|
@@:
|
|
mov eax, [ntfs_cur_iRecord]
|
|
mov [ntfs_attr_iBaseRecord], eax
|
|
mov eax, edi
|
|
jmp .beginfindattr
|
|
.sde:
|
|
popad
|
|
stc
|
|
ret
|
|
.scanlistdone:
|
|
sub ebp, ntfs_attrlist_buf-1Ah
|
|
cmp [ntfs_cur_iRecord], 0
|
|
jnz @f
|
|
sub ebp, ntfs_attrlist_mft_buf-ntfs_attrlist_buf
|
|
@@:
|
|
cmp ebp, 0x400
|
|
jnz .scanlistfound
|
|
inc edx
|
|
push esi edi
|
|
mov esi, ntfs_attrlist_buf+0x200
|
|
mov edi, ntfs_attrlist_buf
|
|
cmp [ntfs_cur_iRecord], 0
|
|
jnz @f
|
|
mov esi, ntfs_attrlist_mft_buf+0x200
|
|
mov edi, ntfs_attrlist_mft_buf
|
|
@@:
|
|
mov ecx, 0x200/4
|
|
rep movsd
|
|
mov eax, edi
|
|
pop edi esi
|
|
sub esi, 0x200
|
|
push [ntfs_cur_offs]
|
|
push [ntfs_cur_size]
|
|
push [ntfs_cur_read]
|
|
push [ntfs_cur_buf]
|
|
push dword [ntfs_attr_size]
|
|
push dword [ntfs_attr_size+4]
|
|
or dword [ntfs_attr_size], -1
|
|
or dword [ntfs_attr_size+4], -1
|
|
mov [ntfs_cur_offs], edx
|
|
mov [ntfs_cur_size], 1
|
|
and [ntfs_cur_read], 0
|
|
mov [ntfs_cur_buf], eax
|
|
mov ecx, [ntfs_attr_list]
|
|
push esi edx
|
|
call .doreadattr
|
|
pop edx esi
|
|
mov ebp, [ntfs_cur_read]
|
|
pop dword [ntfs_attr_size+4]
|
|
pop dword [ntfs_attr_size]
|
|
pop [ntfs_cur_buf]
|
|
pop [ntfs_cur_read]
|
|
pop [ntfs_cur_size]
|
|
pop [ntfs_cur_offs]
|
|
jc .errret
|
|
add ebp, ntfs_attrlist_buf+0x200-0x1A
|
|
cmp [ntfs_cur_iRecord], 0
|
|
jnz .scanliststart
|
|
add ebp, ntfs_attrlist_mft_buf-ntfs_attrlist_buf
|
|
jmp .scanliststart
|
|
|
|
.doreadattr:
|
|
mov [ntfs_bCanContinue], 0
|
|
cmp byte [ecx+8], 0
|
|
jnz .nonresident
|
|
mov eax, [ecx+10h] ; length
|
|
mov esi, eax
|
|
mov edx, [ntfs_cur_offs]
|
|
shr eax, 9
|
|
cmp eax, edx
|
|
jb .okret
|
|
shl edx, 9
|
|
sub esi, edx
|
|
movzx eax, word [ecx+14h]
|
|
add edx, eax
|
|
add edx, ecx ; edx -> data
|
|
mov eax, [ntfs_cur_size]
|
|
cmp eax, (0xFFFFFFFF shr 9)+1
|
|
jbe @f
|
|
mov eax, (0xFFFFFFFF shr 9)+1
|
|
@@:
|
|
shl eax, 9
|
|
cmp eax, esi
|
|
jbe @f
|
|
mov eax, esi
|
|
@@:
|
|
; eax = length, edx -> data
|
|
mov [ntfs_cur_read], eax
|
|
mov ecx, eax
|
|
mov eax, edx
|
|
mov ebx, [ntfs_cur_buf]
|
|
call memmove
|
|
and [ntfs_cur_size], 0 ; CF=0
|
|
ret
|
|
.nonresident:
|
|
; Not all auxiliary records contain correct FileSize info
|
|
mov eax, dword [ntfs_attr_size]
|
|
mov edx, dword [ntfs_attr_size+4]
|
|
push eax
|
|
and eax, edx
|
|
cmp eax, -1
|
|
pop eax
|
|
jnz @f
|
|
mov eax, [ecx+30h] ; FileSize
|
|
mov edx, [ecx+34h]
|
|
mov dword [ntfs_attr_size], eax
|
|
mov dword [ntfs_attr_size+4], edx
|
|
@@:
|
|
add eax, 0x1FF
|
|
adc edx, 0
|
|
shrd eax, edx, 9
|
|
sub eax, [ntfs_cur_offs]
|
|
ja @f
|
|
; return with nothing read
|
|
and [ntfs_cur_size], 0
|
|
.okret:
|
|
clc
|
|
ret
|
|
@@:
|
|
; reduce read length
|
|
and [ntfs_cur_tail], 0
|
|
cmp [ntfs_cur_size], eax
|
|
jb @f
|
|
mov [ntfs_cur_size], eax
|
|
mov eax, dword [ntfs_attr_size]
|
|
and eax, 0x1FF
|
|
mov [ntfs_cur_tail], eax
|
|
@@:
|
|
cmp [ntfs_cur_size], 0
|
|
jz .okret
|
|
mov eax, [ntfs_cur_offs]
|
|
xor edx, edx
|
|
div [ntfs_data.sectors_per_cluster]
|
|
sub eax, [ecx+10h] ; first_vbo
|
|
jb .okret
|
|
; eax = cluster, edx = starting sector
|
|
sub esp, 10h
|
|
movzx esi, word [ecx+20h] ; mcb_info_ofs
|
|
add esi, ecx
|
|
xor ebp, ebp
|
|
.readloop:
|
|
call ntfs_decode_mcb_entry
|
|
jnc .break
|
|
add ebp, [esp+8]
|
|
sub eax, [esp]
|
|
jae .readloop
|
|
push ecx
|
|
push eax
|
|
add eax, [esp+8]
|
|
add eax, ebp
|
|
imul eax, [ntfs_data.sectors_per_cluster]
|
|
add eax, edx
|
|
add eax, [PARTITION_START]
|
|
pop ecx
|
|
neg ecx
|
|
imul ecx, [ntfs_data.sectors_per_cluster]
|
|
sub ecx, edx
|
|
cmp ecx, [ntfs_cur_size]
|
|
jb @f
|
|
mov ecx, [ntfs_cur_size]
|
|
@@:
|
|
mov ebx, [ntfs_cur_buf]
|
|
@@:
|
|
call hd_read
|
|
cmp [hd_error], 0
|
|
jnz .errread2
|
|
add ebx, 0x200
|
|
mov [ntfs_cur_buf], ebx
|
|
inc eax
|
|
add [ntfs_cur_read], 0x200
|
|
dec [ntfs_cur_size]
|
|
inc [ntfs_cur_offs]
|
|
loop @b
|
|
pop ecx
|
|
xor eax, eax
|
|
xor edx, edx
|
|
cmp [ntfs_cur_size], 0
|
|
jnz .readloop
|
|
add esp, 10h
|
|
mov eax, [ntfs_cur_tail]
|
|
test eax, eax
|
|
jz @f
|
|
sub eax, 0x200
|
|
add [ntfs_cur_read], eax
|
|
@@:
|
|
clc
|
|
ret
|
|
.errread2:
|
|
pop ecx
|
|
add esp, 10h
|
|
stc
|
|
ret
|
|
.break:
|
|
add esp, 10h ; CF=0
|
|
mov [ntfs_bCanContinue], 1
|
|
ret
|
|
|
|
ntfs_read_file_record:
|
|
; in: eax=iRecord
|
|
; out: [ntfs_data.frs_buffer] contains information
|
|
; eax=0 - failed, eax=1 - success
|
|
; Read attr $DATA of $Mft, starting from eax*[ntfs_data.frs_size]
|
|
push ecx edx
|
|
mov ecx, [ntfs_data.frs_size]
|
|
mul ecx
|
|
shrd eax, edx, 9
|
|
shr edx, 9
|
|
jnz .err
|
|
push [ntfs_attr_iRecord]
|
|
push [ntfs_attr_iBaseRecord]
|
|
push [ntfs_attr_offs]
|
|
push [ntfs_attr_list]
|
|
push dword [ntfs_attr_size+4]
|
|
push dword [ntfs_attr_size]
|
|
push [ntfs_cur_iRecord]
|
|
push [ntfs_cur_attr]
|
|
push [ntfs_cur_offs]
|
|
push [ntfs_cur_size]
|
|
push [ntfs_cur_buf]
|
|
push [ntfs_cur_read]
|
|
mov [ntfs_cur_attr], 0x80 ; $DATA
|
|
and [ntfs_cur_iRecord], 0 ; $Mft
|
|
mov [ntfs_cur_offs], eax
|
|
shr ecx, 9
|
|
mov [ntfs_cur_size], ecx
|
|
mov eax, [ntfs_data.frs_buffer]
|
|
mov [ntfs_cur_buf], eax
|
|
call ntfs_read_attr
|
|
mov eax, [ntfs_cur_read]
|
|
pop [ntfs_cur_read]
|
|
pop [ntfs_cur_buf]
|
|
pop [ntfs_cur_size]
|
|
pop [ntfs_cur_offs]
|
|
pop [ntfs_cur_attr]
|
|
pop [ntfs_cur_iRecord]
|
|
pop dword [ntfs_attr_size]
|
|
pop dword [ntfs_attr_size+4]
|
|
pop [ntfs_attr_list]
|
|
pop [ntfs_attr_offs]
|
|
pop [ntfs_attr_iBaseRecord]
|
|
pop [ntfs_attr_iRecord]
|
|
pop edx ecx
|
|
jc .errret
|
|
cmp eax, [ntfs_data.frs_size]
|
|
jnz .errret
|
|
mov eax, [ntfs_data.frs_buffer]
|
|
cmp dword [eax], 'FILE'
|
|
jnz .errret
|
|
push ebx
|
|
mov ebx, eax
|
|
call ntfs_restore_usa_frs
|
|
pop ebx
|
|
setnc al
|
|
movzx eax, al
|
|
.ret:
|
|
ret
|
|
.err:
|
|
pop edx ecx
|
|
.errret:
|
|
xor eax, eax
|
|
ret
|
|
|
|
ntfs_restore_usa_frs:
|
|
mov eax, [ntfs_data.frs_size]
|
|
ntfs_restore_usa:
|
|
pushad
|
|
shr eax, 9
|
|
mov ecx, eax
|
|
inc eax
|
|
cmp [ebx+6], ax
|
|
jnz .err
|
|
movzx eax, word [ebx+4]
|
|
lea esi, [eax+ebx]
|
|
lodsw
|
|
mov edx, eax
|
|
lea edi, [ebx+0x1FE]
|
|
@@:
|
|
cmp [edi], dx
|
|
jnz .err
|
|
lodsw
|
|
stosw
|
|
add edi, 0x1FE
|
|
loop @b
|
|
popad
|
|
clc
|
|
ret
|
|
.err:
|
|
popad
|
|
stc
|
|
ret
|
|
|
|
ntfs_decode_mcb_entry:
|
|
push eax ecx edi
|
|
lea edi, [esp+16]
|
|
xor eax, eax
|
|
lodsb
|
|
test al, al
|
|
jz .end
|
|
mov ecx, eax
|
|
and ecx, 0xF
|
|
cmp ecx, 8
|
|
ja .end
|
|
push ecx
|
|
rep movsb
|
|
pop ecx
|
|
sub ecx, 8
|
|
neg ecx
|
|
cmp byte [esi-1], 80h
|
|
jae .end
|
|
push eax
|
|
xor eax, eax
|
|
rep stosb
|
|
pop ecx
|
|
shr ecx, 4
|
|
cmp ecx, 8
|
|
ja .end
|
|
push ecx
|
|
rep movsb
|
|
pop ecx
|
|
sub ecx, 8
|
|
neg ecx
|
|
cmp byte [esi-1], 80h
|
|
cmc
|
|
sbb eax, eax
|
|
rep stosb
|
|
stc
|
|
.end:
|
|
pop edi ecx eax
|
|
ret
|
|
|
|
unichar_toupper:
|
|
push eax
|
|
call uni2ansi_char
|
|
cmp al, '_'
|
|
jz .unk
|
|
add esp, 4
|
|
call char_toupper
|
|
jmp ansi2uni_char
|
|
.unk:
|
|
pop eax
|
|
ret
|
|
|
|
ntfs_find_lfn:
|
|
; in: esi+ebp -> name
|
|
; out: CF=1 - file not found
|
|
; else CF=0, [ntfs_cur_iRecord] valid, eax->record in parent directory
|
|
mov [ntfs_cur_iRecord], 5 ; start parse from root cluster
|
|
.doit2:
|
|
mov [ntfs_cur_attr], 0x90 ; $INDEX_ROOT
|
|
and [ntfs_cur_offs], 0
|
|
mov eax, [ntfs_data.cur_index_size]
|
|
mov [ntfs_cur_size], eax
|
|
mov eax, [ntfs_data.cur_index_buf]
|
|
mov [ntfs_cur_buf], eax
|
|
call ntfs_read_attr
|
|
jnc @f
|
|
.ret:
|
|
ret
|
|
@@:
|
|
cmp [ntfs_cur_read], 0x20
|
|
jc .ret
|
|
pushad
|
|
mov esi, [ntfs_data.cur_index_buf]
|
|
mov eax, [esi+14h]
|
|
add eax, 10h
|
|
cmp [ntfs_cur_read], eax
|
|
jae .readok1
|
|
add eax, 1FFh
|
|
shr eax, 9
|
|
cmp eax, [ntfs_data.cur_index_size]
|
|
ja @f
|
|
.stc_ret:
|
|
popad
|
|
stc
|
|
ret
|
|
@@:
|
|
; reallocate
|
|
push eax
|
|
push [ntfs_data.cur_index_buf]
|
|
call kernel_free
|
|
pop eax
|
|
mov [ntfs_data.cur_index_size], eax
|
|
push eax
|
|
call kernel_alloc
|
|
test eax, eax
|
|
jnz @f
|
|
and [ntfs_data.cur_index_size], 0
|
|
and [ntfs_data.cur_index_buf], 0
|
|
jmp .stc_ret
|
|
@@:
|
|
mov [ntfs_data.cur_index_buf], eax
|
|
popad
|
|
jmp .doit2
|
|
.readok1:
|
|
mov ebp, [esi+8] ; subnode_size
|
|
shr ebp, 9
|
|
cmp ebp, [ntfs_data.cur_index_size]
|
|
jbe .ok2
|
|
push esi ebp
|
|
push ebp
|
|
call kernel_alloc
|
|
pop ebp esi
|
|
test eax, eax
|
|
jz .stc_ret
|
|
mov edi, eax
|
|
mov ecx, [ntfs_data.cur_index_size]
|
|
shl ecx, 9-2
|
|
rep movsd
|
|
mov esi, eax
|
|
mov [ntfs_data.cur_index_size], ebp
|
|
push esi ebp
|
|
push [ntfs_data.cur_index_buf]
|
|
call kernel_free
|
|
pop ebp esi
|
|
mov [ntfs_data.cur_index_buf], esi
|
|
.ok2:
|
|
add esi, 10h
|
|
mov edi, [esp+4]
|
|
; edi -> name, esi -> current index data, ebp = subnode size
|
|
.scanloop:
|
|
add esi, [esi]
|
|
.scanloopint:
|
|
test byte [esi+0Ch], 2
|
|
jnz .subnode
|
|
push esi
|
|
add esi, 0x52
|
|
movzx ecx, byte [esi-2]
|
|
push edi
|
|
@@:
|
|
lodsw
|
|
call unichar_toupper
|
|
push eax
|
|
mov al, [edi]
|
|
inc edi
|
|
cmp al, '/'
|
|
jz .slash
|
|
call char_toupper
|
|
call ansi2uni_char
|
|
cmp ax, [esp]
|
|
pop eax
|
|
loopz @b
|
|
jz .found
|
|
pop edi
|
|
pop esi
|
|
jb .subnode
|
|
.scanloopcont:
|
|
movzx eax, word [esi+8]
|
|
add esi, eax
|
|
jmp .scanloopint
|
|
.slash:
|
|
pop eax
|
|
pop edi
|
|
pop esi
|
|
.subnode:
|
|
test byte [esi+0Ch], 1
|
|
jz .notfound
|
|
movzx eax, word [esi+8]
|
|
mov eax, [esi+eax-8]
|
|
mul [ntfs_data.sectors_per_cluster]
|
|
mov [ntfs_cur_offs], eax
|
|
mov [ntfs_cur_attr], 0xA0 ; $INDEX_ALLOCATION
|
|
mov [ntfs_cur_size], ebp
|
|
mov eax, [ntfs_data.cur_index_buf]
|
|
mov esi, eax
|
|
mov [ntfs_cur_buf], eax
|
|
call ntfs_read_attr
|
|
mov eax, ebp
|
|
shl eax, 9
|
|
cmp [ntfs_cur_read], eax
|
|
jnz .notfound
|
|
cmp dword [esi], 'INDX'
|
|
jnz .notfound
|
|
mov ebx, esi
|
|
call ntfs_restore_usa
|
|
jc .notfound
|
|
add esi, 0x18
|
|
jmp .scanloop
|
|
.notfound:
|
|
popad
|
|
stc
|
|
ret
|
|
.found:
|
|
cmp byte [edi], 0
|
|
jz .done
|
|
cmp byte [edi], '/'
|
|
jz .next
|
|
pop edi
|
|
pop esi
|
|
jmp .scanloopcont
|
|
.done:
|
|
.next:
|
|
pop esi
|
|
pop esi
|
|
mov eax, [esi]
|
|
mov [ntfs_cur_iRecord], eax
|
|
mov [esp+1Ch], esi
|
|
mov [esp+4], edi
|
|
popad
|
|
inc esi
|
|
cmp byte [esi-1], 0
|
|
jnz .doit2
|
|
test ebp, ebp
|
|
jz @f
|
|
mov esi, ebp
|
|
xor ebp, ebp
|
|
jmp .doit2
|
|
@@:
|
|
ret
|
|
|
|
;----------------------------------------------------------------
|
|
;
|
|
; ntfs_HdRead - read NTFS hard disk
|
|
;
|
|
; esi points to filename
|
|
; ebx pointer to 64-bit number = first wanted byte, 0+
|
|
; may be ebx=0 - start from first byte
|
|
; ecx number of bytes to read, 0+
|
|
; edx mem location to return data
|
|
;
|
|
; ret ebx = bytes read or 0xffffffff file not found
|
|
; eax = 0 ok read or other = errormsg
|
|
;
|
|
;--------------------------------------------------------------
|
|
ntfs_HdRead:
|
|
cmp byte [esi], 0
|
|
jnz @f
|
|
or ebx, -1
|
|
movi eax, ERROR_ACCESS_DENIED
|
|
ret
|
|
@@:
|
|
call ntfs_find_lfn
|
|
jnc .found
|
|
or ebx, -1
|
|
movi eax, ERROR_FILE_NOT_FOUND
|
|
ret
|
|
.found:
|
|
mov [ntfs_cur_attr], 0x80 ; $DATA
|
|
and [ntfs_cur_offs], 0
|
|
and [ntfs_cur_size], 0
|
|
call ntfs_read_attr
|
|
jnc @f
|
|
or ebx, -1
|
|
movi eax, ERROR_ACCESS_DENIED
|
|
ret
|
|
@@:
|
|
pushad
|
|
and dword [esp+10h], 0
|
|
xor eax, eax
|
|
test ebx, ebx
|
|
jz .zero1
|
|
cmp dword [ebx+4], 0x200
|
|
jb @f
|
|
.eof0:
|
|
popad
|
|
xor ebx, ebx
|
|
.eof:
|
|
movi eax, ERROR_END_OF_FILE
|
|
ret
|
|
@@:
|
|
mov eax, [ebx]
|
|
test eax, 0x1FF
|
|
jz .alignedstart
|
|
push edx
|
|
mov edx, [ebx+4]
|
|
shrd eax, edx, 9
|
|
pop edx
|
|
mov [ntfs_cur_offs], eax
|
|
mov [ntfs_cur_size], 1
|
|
mov [ntfs_cur_buf], ntfs_bitmap_buf
|
|
call ntfs_read_attr.continue
|
|
mov eax, [ebx]
|
|
and eax, 0x1FF
|
|
lea esi, [ntfs_bitmap_buf+eax]
|
|
sub eax, [ntfs_cur_read]
|
|
jae .eof0
|
|
neg eax
|
|
push ecx
|
|
cmp ecx, eax
|
|
jb @f
|
|
mov ecx, eax
|
|
@@:
|
|
mov [esp+10h+4], ecx
|
|
mov edi, edx
|
|
rep movsb
|
|
mov edx, edi
|
|
pop ecx
|
|
sub ecx, [esp+10h]
|
|
jnz @f
|
|
.retok:
|
|
popad
|
|
xor eax, eax
|
|
ret
|
|
@@:
|
|
cmp [ntfs_cur_read], 0x200
|
|
jz .alignedstart
|
|
.eof_ebx:
|
|
popad
|
|
jmp .eof
|
|
.alignedstart:
|
|
mov eax, [ebx]
|
|
push edx
|
|
mov edx, [ebx+4]
|
|
add eax, 511
|
|
adc edx, 0
|
|
shrd eax, edx, 9
|
|
pop edx
|
|
.zero1:
|
|
mov [ntfs_cur_offs], eax
|
|
mov [ntfs_cur_buf], edx
|
|
mov eax, ecx
|
|
shr eax, 9
|
|
mov [ntfs_cur_size], eax
|
|
add eax, [ntfs_cur_offs]
|
|
push eax
|
|
call ntfs_read_attr.continue
|
|
pop [ntfs_cur_offs]
|
|
mov eax, [ntfs_cur_read]
|
|
add [esp+10h], eax
|
|
mov eax, ecx
|
|
and eax, not 0x1FF
|
|
cmp [ntfs_cur_read], eax
|
|
jnz .eof_ebx
|
|
and ecx, 0x1FF
|
|
jz .retok
|
|
add edx, [ntfs_cur_read]
|
|
mov [ntfs_cur_size], 1
|
|
mov [ntfs_cur_buf], ntfs_bitmap_buf
|
|
call ntfs_read_attr.continue
|
|
cmp [ntfs_cur_read], ecx
|
|
jb @f
|
|
mov [ntfs_cur_read], ecx
|
|
@@:
|
|
xchg ecx, [ntfs_cur_read]
|
|
push ecx
|
|
mov edi, edx
|
|
mov esi, ntfs_bitmap_buf
|
|
add [esp+10h+4], ecx
|
|
rep movsb
|
|
pop ecx
|
|
xor eax, eax
|
|
cmp ecx, [ntfs_cur_read]
|
|
jz @f
|
|
mov al, ERROR_END_OF_FILE
|
|
@@:
|
|
mov [esp+1Ch], eax
|
|
popad
|
|
ret
|
|
|
|
;----------------------------------------------------------------
|
|
;
|
|
; ntfs_HdReadFolder - read NTFS hard disk folder
|
|
;
|
|
; esi points to filename
|
|
; ebx pointer to structure 32-bit number = first wanted block, 0+
|
|
; & flags (bitfields)
|
|
; flags: bit 0: 0=ANSI names, 1=UNICODE names
|
|
; ecx number of blocks to read, 0+
|
|
; edx mem location to return data
|
|
;
|
|
; ret ebx = blocks read or 0xffffffff folder not found
|
|
; eax = 0 ok read or other = errormsg
|
|
;
|
|
;--------------------------------------------------------------
|
|
ntfs_HdReadFolder:
|
|
mov eax, 5 ; root cluster
|
|
cmp byte [esi], 0
|
|
jz .doit
|
|
call ntfs_find_lfn
|
|
jnc .doit2
|
|
.notfound:
|
|
or ebx, -1
|
|
push ERROR_FILE_NOT_FOUND
|
|
.pop_ret:
|
|
pop eax
|
|
ret
|
|
.doit:
|
|
mov [ntfs_cur_iRecord], eax
|
|
.doit2:
|
|
mov [ntfs_cur_attr], 0x10 ; $STANDARD_INFORMATION
|
|
and [ntfs_cur_offs], 0
|
|
mov [ntfs_cur_size], 1
|
|
mov [ntfs_cur_buf], ntfs_bitmap_buf
|
|
call ntfs_read_attr
|
|
jc .notfound
|
|
mov [ntfs_cur_attr], 0x90 ; $INDEX_ROOT
|
|
and [ntfs_cur_offs], 0
|
|
mov eax, [ntfs_data.cur_index_size]
|
|
mov [ntfs_cur_size], eax
|
|
mov eax, [ntfs_data.cur_index_buf]
|
|
mov [ntfs_cur_buf], eax
|
|
call ntfs_read_attr
|
|
jnc .ok
|
|
cmp [hd_error], 0
|
|
jz .notfound
|
|
or ebx, -1
|
|
push 11
|
|
jmp .pop_ret
|
|
.ok:
|
|
cmp [ntfs_cur_read], 0x20
|
|
jae @f
|
|
or ebx, -1
|
|
.fserr:
|
|
push ERROR_FAT_TABLE
|
|
jmp .pop_ret
|
|
@@:
|
|
pushad
|
|
mov esi, [ntfs_data.cur_index_buf]
|
|
mov eax, [esi+14h]
|
|
add eax, 10h
|
|
cmp [ntfs_cur_read], eax
|
|
jae .readok1
|
|
add eax, 1FFh
|
|
shr eax, 9
|
|
cmp eax, [ntfs_data.cur_index_size]
|
|
ja @f
|
|
popad
|
|
jmp .fserr
|
|
@@:
|
|
; reallocate
|
|
push eax
|
|
push [ntfs_data.cur_index_buf]
|
|
call kernel_free
|
|
pop eax
|
|
mov [ntfs_data.cur_index_size], eax
|
|
push eax
|
|
call kernel_alloc
|
|
test eax, eax
|
|
jnz @f
|
|
and [ntfs_data.cur_index_size], 0
|
|
and [ntfs_data.cur_index_buf], 0
|
|
.nomem:
|
|
popad
|
|
or ebx, -1
|
|
movi eax, 12
|
|
ret
|
|
@@:
|
|
mov [ntfs_data.cur_index_buf], eax
|
|
popad
|
|
jmp .doit2
|
|
.readok1:
|
|
mov ebp, [esi+8] ; subnode_size
|
|
shr ebp, 9
|
|
cmp ebp, [ntfs_data.cur_index_size]
|
|
jbe .ok2
|
|
push esi ebp
|
|
push ebp
|
|
call kernel_alloc
|
|
pop ebp esi
|
|
test eax, eax
|
|
jz .nomem
|
|
mov edi, eax
|
|
mov ecx, [ntfs_data.cur_index_size]
|
|
shl ecx, 9-2
|
|
rep movsd
|
|
mov esi, eax
|
|
mov [ntfs_data.cur_index_size], ebp
|
|
push esi ebp
|
|
push [ntfs_data.cur_index_buf]
|
|
call kernel_free
|
|
pop ebp esi
|
|
mov [ntfs_data.cur_index_buf], esi
|
|
.ok2:
|
|
add esi, 10h
|
|
mov ebx, [esp+10h]
|
|
mov edx, [esp+14h]
|
|
push dword [ebx+4] ; read ANSI/UNICODE name
|
|
mov ebx, [ebx]
|
|
; init header
|
|
mov edi, edx
|
|
mov ecx, 32/4
|
|
xor eax, eax
|
|
rep stosd
|
|
mov byte [edx], 1 ; version
|
|
mov ecx, [esp+4+18h]
|
|
push edx
|
|
mov edx, esp
|
|
; edi -> BDFE, esi -> current index data, ebp = subnode size, ebx = first wanted block,
|
|
; ecx = number of blocks to read
|
|
; edx -> parameters block: dd <output>, dd <flags>
|
|
cmp [ntfs_cur_iRecord], 5
|
|
jz .skip_specials
|
|
; dot and dotdot entries
|
|
push esi
|
|
xor esi, esi
|
|
call .add_special_entry
|
|
inc esi
|
|
call .add_special_entry
|
|
pop esi
|
|
.skip_specials:
|
|
; at first, dump index root
|
|
add esi, [esi]
|
|
.dump_root:
|
|
test byte [esi+0Ch], 2
|
|
jnz .dump_root_done
|
|
call .add_entry
|
|
movzx eax, word [esi+8]
|
|
add esi, eax
|
|
jmp .dump_root
|
|
.dump_root_done:
|
|
; now dump all subnodes
|
|
push ecx edi
|
|
mov edi, ntfs_bitmap_buf
|
|
mov [ntfs_cur_buf], edi
|
|
mov ecx, 0x400/4
|
|
xor eax, eax
|
|
rep stosd
|
|
mov [ntfs_cur_attr], 0xB0 ; $BITMAP
|
|
and [ntfs_cur_offs], 0
|
|
mov [ntfs_cur_size], 2
|
|
call ntfs_read_attr
|
|
pop edi ecx
|
|
push 0 ; save offset in $BITMAP attribute
|
|
and [ntfs_cur_offs], 0
|
|
.dumploop:
|
|
mov [ntfs_cur_attr], 0xA0
|
|
mov [ntfs_cur_size], ebp
|
|
mov eax, [ntfs_data.cur_index_buf]
|
|
mov esi, eax
|
|
mov [ntfs_cur_buf], eax
|
|
push [ntfs_cur_offs]
|
|
mov eax, [ntfs_cur_offs]
|
|
imul eax, ebp
|
|
mov [ntfs_cur_offs], eax
|
|
call ntfs_read_attr
|
|
pop [ntfs_cur_offs]
|
|
mov eax, ebp
|
|
shl eax, 9
|
|
cmp [ntfs_cur_read], eax
|
|
jnz .done
|
|
push eax
|
|
mov eax, [ntfs_cur_offs]
|
|
and eax, 0x400*8-1
|
|
bt dword [ntfs_bitmap_buf], eax
|
|
pop eax
|
|
jnc .dump_subnode_done
|
|
cmp dword [esi], 'INDX'
|
|
jnz .dump_subnode_done
|
|
push ebx
|
|
mov ebx, esi
|
|
call ntfs_restore_usa
|
|
pop ebx
|
|
jc .dump_subnode_done
|
|
add esi, 0x18
|
|
add esi, [esi]
|
|
.dump_subnode:
|
|
test byte [esi+0Ch], 2
|
|
jnz .dump_subnode_done
|
|
call .add_entry
|
|
movzx eax, word [esi+8]
|
|
add esi, eax
|
|
jmp .dump_subnode
|
|
.dump_subnode_done:
|
|
inc [ntfs_cur_offs]
|
|
test [ntfs_cur_offs], 0x400*8-1
|
|
jnz .dumploop
|
|
mov [ntfs_cur_attr], 0xB0
|
|
push ecx edi
|
|
mov edi, ntfs_bitmap_buf
|
|
mov [ntfs_cur_buf], edi
|
|
mov ecx, 0x400/4
|
|
xor eax, eax
|
|
rep stosd
|
|
pop edi ecx
|
|
pop eax
|
|
push [ntfs_cur_offs]
|
|
inc eax
|
|
mov [ntfs_cur_offs], eax
|
|
mov [ntfs_cur_size], 2
|
|
push eax
|
|
call ntfs_read_attr
|
|
pop eax
|
|
pop [ntfs_cur_offs]
|
|
push eax
|
|
jmp .dumploop
|
|
.done:
|
|
pop eax
|
|
pop edx
|
|
mov ebx, [edx+4]
|
|
pop edx
|
|
xor eax, eax
|
|
dec ecx
|
|
js @f
|
|
mov al, ERROR_END_OF_FILE
|
|
@@:
|
|
mov [esp+1Ch], eax
|
|
mov [esp+10h], ebx
|
|
popad
|
|
ret
|
|
|
|
.add_special_entry:
|
|
mov eax, [edx]
|
|
inc dword [eax+8] ; new file found
|
|
dec ebx
|
|
jns .ret
|
|
dec ecx
|
|
js .ret
|
|
inc dword [eax+4] ; new file block copied
|
|
mov eax, [edx+4]
|
|
mov [edi+4], eax
|
|
; mov eax, dword [ntfs_bitmap_buf+0x20]
|
|
; or al, 0x10
|
|
mov eax, 0x10
|
|
stosd
|
|
scasd
|
|
push edx
|
|
mov eax, dword [ntfs_bitmap_buf]
|
|
mov edx, dword [ntfs_bitmap_buf+4]
|
|
call ntfs_datetime_to_bdfe
|
|
mov eax, dword [ntfs_bitmap_buf+0x18]
|
|
mov edx, dword [ntfs_bitmap_buf+0x1C]
|
|
call ntfs_datetime_to_bdfe
|
|
mov eax, dword [ntfs_bitmap_buf+8]
|
|
mov edx, dword [ntfs_bitmap_buf+0xC]
|
|
call ntfs_datetime_to_bdfe
|
|
pop edx
|
|
xor eax, eax
|
|
stosd
|
|
stosd
|
|
mov al, '.'
|
|
push edi ecx
|
|
lea ecx, [esi+1]
|
|
test byte [edi-0x24], 1
|
|
jz @f
|
|
rep stosw
|
|
pop ecx
|
|
xor eax, eax
|
|
stosw
|
|
pop edi
|
|
add edi, 520
|
|
ret
|
|
@@:
|
|
rep stosb
|
|
pop ecx
|
|
xor eax, eax
|
|
stosb
|
|
pop edi
|
|
add edi, 264
|
|
.ret:
|
|
ret
|
|
|
|
.add_entry:
|
|
; do not return DOS 8.3 names
|
|
cmp byte [esi+0x51], 2
|
|
jz .ret
|
|
; do not return system files
|
|
; ... note that there will be no bad effects if system files also were reported ...
|
|
cmp dword [esi], 0x10
|
|
jb .ret
|
|
mov eax, [edx]
|
|
inc dword [eax+8] ; new file found
|
|
dec ebx
|
|
jns .ret
|
|
dec ecx
|
|
js .ret
|
|
inc dword [eax+4] ; new file block copied
|
|
mov eax, [edx+4] ; flags
|
|
call ntfs_direntry_to_bdfe
|
|
push ecx esi edi
|
|
movzx ecx, byte [esi+0x50]
|
|
add esi, 0x52
|
|
test byte [edi-0x24], 1
|
|
jz .ansi
|
|
shr ecx, 1
|
|
rep movsd
|
|
adc ecx, ecx
|
|
rep movsw
|
|
and word [edi], 0
|
|
pop edi
|
|
add edi, 520
|
|
pop esi ecx
|
|
ret
|
|
.ansi:
|
|
jecxz .skip
|
|
@@:
|
|
lodsw
|
|
call uni2ansi_char
|
|
stosb
|
|
loop @b
|
|
.skip:
|
|
xor al, al
|
|
stosb
|
|
pop edi
|
|
add edi, 264
|
|
pop esi ecx
|
|
ret
|
|
|
|
ntfs_direntry_to_bdfe:
|
|
mov [edi+4], eax ; ANSI/UNICODE name
|
|
mov eax, [esi+48h]
|
|
test eax, 0x10000000
|
|
jz @f
|
|
and eax, not 0x10000000
|
|
or al, 0x10
|
|
@@:
|
|
stosd
|
|
scasd
|
|
push edx
|
|
mov eax, [esi+0x18]
|
|
mov edx, [esi+0x1C]
|
|
call ntfs_datetime_to_bdfe
|
|
mov eax, [esi+0x30]
|
|
mov edx, [esi+0x34]
|
|
call ntfs_datetime_to_bdfe
|
|
mov eax, [esi+0x20]
|
|
mov edx, [esi+0x24]
|
|
call ntfs_datetime_to_bdfe
|
|
pop edx
|
|
mov eax, [esi+0x40]
|
|
stosd
|
|
mov eax, [esi+0x44]
|
|
stosd
|
|
ret
|
|
|
|
iglobal
|
|
_24 dd 24
|
|
_60 dd 60
|
|
_10000000 dd 10000000
|
|
days400year dd 365*400+100-4+1
|
|
days100year dd 365*100+25-1
|
|
days4year dd 365*4+1
|
|
days1year dd 365
|
|
months dd 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
|
months2 dd 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
|
_400 dd 400
|
|
_100 dd 100
|
|
endg
|
|
|
|
ntfs_datetime_to_bdfe:
|
|
; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC
|
|
push eax
|
|
mov eax, edx
|
|
xor edx, edx
|
|
div [_10000000]
|
|
xchg eax, [esp]
|
|
div [_10000000]
|
|
pop edx
|
|
.sec:
|
|
; edx:eax = number of seconds since January 1, 1601
|
|
push eax
|
|
mov eax, edx
|
|
xor edx, edx
|
|
div [_60]
|
|
xchg eax, [esp]
|
|
div [_60]
|
|
mov [edi], dl
|
|
pop edx
|
|
; edx:eax = number of minutes
|
|
div [_60]
|
|
mov [edi+1], dl
|
|
; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32)
|
|
xor edx, edx
|
|
div [_24]
|
|
mov [edi+2], dl
|
|
mov [edi+3], byte 0
|
|
; eax = number of days since January 1, 1601
|
|
xor edx, edx
|
|
div [days400year]
|
|
imul eax, 400
|
|
add eax, 1601
|
|
mov [edi+6], ax
|
|
mov eax, edx
|
|
xor edx, edx
|
|
div [days100year]
|
|
cmp al, 4
|
|
jnz @f
|
|
dec eax
|
|
add edx, [days100year]
|
|
@@:
|
|
imul eax, 100
|
|
add [edi+6], ax
|
|
mov eax, edx
|
|
xor edx, edx
|
|
div [days4year]
|
|
shl eax, 2
|
|
add [edi+6], ax
|
|
mov eax, edx
|
|
xor edx, edx
|
|
div [days1year]
|
|
cmp al, 4
|
|
jnz @f
|
|
dec eax
|
|
add edx, [days1year]
|
|
@@:
|
|
add [edi+6], ax
|
|
push esi edx
|
|
mov esi, months
|
|
movzx eax, word [edi+6]
|
|
test al, 3
|
|
jnz .noleap
|
|
xor edx, edx
|
|
push eax
|
|
div [_400]
|
|
pop eax
|
|
test edx, edx
|
|
jz .leap
|
|
xor edx, edx
|
|
div [_100]
|
|
test edx, edx
|
|
jz .noleap
|
|
.leap:
|
|
mov esi, months2
|
|
.noleap:
|
|
pop edx
|
|
xor eax, eax
|
|
inc eax
|
|
@@:
|
|
sub edx, [esi]
|
|
jb @f
|
|
add esi, 4
|
|
inc eax
|
|
jmp @b
|
|
@@:
|
|
add edx, [esi]
|
|
pop esi
|
|
inc edx
|
|
mov [edi+4], dl
|
|
mov [edi+5], al
|
|
add edi, 8
|
|
ret
|
|
|
|
;----------------------------------------------------------------
|
|
;
|
|
; ntfs_HdRewrite - write to NTFS hard disk
|
|
;
|
|
; esi points to filename
|
|
; ebx ignored (reserved)
|
|
; ecx number of bytes to write, 0+
|
|
; edx mem location to data
|
|
;
|
|
; ret ebx = number of written bytes
|
|
; eax = 0 ok read or other = errormsg
|
|
;
|
|
;--------------------------------------------------------------
|
|
ntfs_HdRewrite:
|
|
xor ebx, ebx
|
|
mov eax, ERROR_UNSUPPORTED_FS
|
|
ret
|
|
|
|
;----------------------------------------------------------------
|
|
;
|
|
; ntfs_HdWrite - write to NTFS hard disk
|
|
;
|
|
; esi points to filename
|
|
; ebx pointer to 64-bit number = first wanted byte, 0+
|
|
; may be ebx=0 - start from first byte
|
|
; ecx number of bytes to write, 0+
|
|
; edx mem location to data
|
|
;
|
|
; ret ebx = bytes written (maybe 0)
|
|
; eax = 0 ok write or other = errormsg
|
|
;
|
|
;--------------------------------------------------------------
|
|
ntfs_HdWrite:
|
|
xor ebx, ebx
|
|
mov eax, ERROR_UNSUPPORTED_FS
|
|
ret
|
|
|
|
;----------------------------------------------------------------
|
|
;
|
|
; ntfs_HdSetFileEnd - set end of file on NTFS hard disk
|
|
;
|
|
; esi points to filename
|
|
; ebx points to 64-bit number = new file size
|
|
; ecx ignored (reserved)
|
|
; edx ignored (reserved)
|
|
;
|
|
; ret eax = 0 ok or other = errormsg
|
|
;
|
|
;--------------------------------------------------------------
|
|
ntfs_HdSetFileEnd:
|
|
ntfs_HdSetFileInfo:
|
|
;----------------------------------------------------------------
|
|
;
|
|
; ntfs_HdDelete - delete file or empty folder from NTFS hard disk
|
|
;
|
|
; esi points to filename
|
|
;
|
|
; ret eax = 0 ok or other = errormsg
|
|
;
|
|
;--------------------------------------------------------------
|
|
ntfs_HdDelete:
|
|
mov eax, ERROR_UNSUPPORTED_FS
|
|
ret
|
|
|
|
ntfs_HdGetFileInfo:
|
|
cmp byte [esi], 0
|
|
jnz @f
|
|
movi eax, 2
|
|
ret
|
|
@@:
|
|
call ntfs_find_lfn
|
|
jnc .doit
|
|
movi eax, ERROR_FILE_NOT_FOUND
|
|
cmp [hd_error], 0
|
|
jz @f
|
|
mov al, 11
|
|
@@:
|
|
ret
|
|
.doit:
|
|
push esi edi
|
|
mov esi, eax
|
|
mov edi, edx
|
|
xor eax, eax
|
|
call ntfs_direntry_to_bdfe
|
|
pop edi esi
|
|
xor eax, eax
|
|
ret
|
|
|