Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 2782 → Rev 2783

/programs/hd_load/mtldr_install/mtldr_code/compile.bat
0,0 → 1,0
fasm mtldr.asm ..\mtldr_for_installer
/programs/hd_load/mtldr_install/mtldr_code/fat32.inc
0,0 → 1,112
fat32_parse_dir:
; in: eax=directory cluster
; out: eax=entry cluster
mov bx, 900h
mov di, bx
push eax
call read_cluster
mov cx, word [cluster_size]
shr cx, 5 ; div 20h
.scan_cluster:
pop eax
cmp byte [di], 0
jz file_not_found
mov si, [esp+2]
push eax
call fat_compare_name
jz .file_found
and di, not 1Fh
add di, 20h
loop .scan_cluster
pop eax
call next_cluster
jnc file_not_found
jc fat32_parse_dir
.file_found:
pop eax
mov si, [esp+2]
mov [cur_obj], si
and di, not 1Fh
mov si, directory_string
mov ax, [di+14h]
shl eax, 10h
mov ax, [di+1Ah]
test eax, eax
mov si, nodata_string
jz find_error_si
ret 2
 
fat_compare_name:
push cx
mov cx, 9
.scan:
lodsb
cmp al, '.'
jz .ext
cmp al, 0
jz .nameend
cmp al, 'a'
jb .notletter
cmp al, 'z'
ja .notletter
or byte [di], 20h
.notletter:
scasb
loopz .scan
.notfound:
inc cx ; to clear ZF flag
pop cx
ret
.ext:
mov al, ' '
dec cx
repz scasb
jnz .notfound
test di, 1
jnz .notfound
mov cx, 4
jmp .scan
.nameend:
mov al, ' '
dec cx
repz scasb
jnz .notfound
test di, 1
jnz .file_found
mov cx, 3
repz scasb
jnz .notfound
.file_found:
xor cx, cx ; to set ZF flag
pop cx
ret
 
read_cluster:
; in: eax=cluster,bx->buffer
and eax, 0FFFFFFFh
movzx ecx, byte [50Dh] ; sects_per_clust
mul ecx
add eax, [data_start]
; call read
; ret
jmp relative_read
next_cluster:
mov bx, 700h
; sector is 200h bytes long, one entry in FAT occupies 4 bytes => 80h entries in sector
push eax
shr eax, 7 ; div 80h
cmp eax, [fat_cur_sector]
jz @f
mov [fat_cur_sector], eax
add eax, [fat_start]
mov cx, 1
call relative_read
@@:
pop eax
and eax, 7Fh
mov eax, [700h+eax*4]
and eax, 0FFFFFFFh
cmp eax, 0FFFFFF7h
mov si, bad_cluster_string
jz find_error_si
ret
/programs/hd_load/mtldr_install/mtldr_code/mtldr.asm
0,0 → 1,786
; KolibriOS bootloader
; this code has been written by diamond in 2005,2006 specially for KolibriOS
 
; this code is loaded by ntldr to 0D00:0000
; and by io.sys from config.sys to xxxx:0100
; and by bootmgr in vista to 0000:7C00
format binary
use16
 
org 0xD000
 
; entry point for 9x booting
call @f
; db 'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
db 'NTFS'
 
; file offset +7
; may be changed by installator
boot_drive db 80h
partition_start dd -1
imgnameofs dw menuet_img_name
 
@@:
pop si
sub si, 3
cmp si, 7C00h
jz boot_vista
mov si, load_question + 100h - 0D000h
call out_string
mov si, answer + 100h - 0D000h
xxy: mov ah, 0
int 16h
or al, 20h
mov [si], al
cmp al, 'y'
jz xxz
cmp al, 'n'
jnz xxy
; continue load Windows
; call out_string
; ret
out_string:
lodsb
test al, al
jz .xxx
mov ah, 0Eh
mov bx, 7
int 10h
jmp out_string
.xxx: ret
xxz:
; boot KolibriOS
call out_string
push 0
pop ds
mov word [4], new01handler + 100h - 0D000h
mov [6], cs
pushf
pop ax
or ah, 1
push ax
popf
; int 19h
; pushf ; there will be no iret
call far [19h*4]
xxt:
; TF has been cleared when entered new01handler
; pushf
; pop ax
; and ah, not 1
; push ax
; popf
push 0
pop ds
cmp word [8*4+2], 0F000h
jz @f
les bx, [8*4]
mov eax, [es:bx+1]
mov [8*4], eax
@@:
mov si, 100h
boot_vista:
xor di, di
push cs
pop ds
push 0D00h
pop es
mov cx, 2000h/2
rep movsw
jmp 0D00h:0256h
 
new01handler:
; [sp]=ip, [sp+2]=cs, [sp+4]=flags
push bp
mov bp, sp
push bx
push ds
lds bx, [bp+2]
cmp word [bx], 19cdh
jz xxt
pop ds
pop bx
pop bp
iret
 
relative_read:
add eax, [partition_start]
 
; read from hard disk
; drive_size must be already initialized
; in: eax = absolute sector
; cx = number of sectors
; es:bx -> buffer
read:
pushad
cmp eax, [drive_size]
jb .old_style
xor dx, dx
; new style - LBA, function 42
cmp [has_lba], dl
jz disk_error
; allocate disk address packet on the stack
; qword +8: absolute block number
push dx
push dx
; push dword 0 ; dword +C is high dword
push eax ; dword +8 is low dword
; dword +4: buffer address
push es ; word +6 is segment
push bx ; word +4 is offset
; word +2: number of blocks = 1
push 1
; word +0: size of packet = 10h
push 10h
; now pair ss:sp contain address of disk address packet
.patch1:
mov ax, 4200h
mov dl, [boot_drive]
mov si, sp
push ds
push ss
pop ds
int 13h
pop ds
lea sp, [si+10h]
.end:
popad
jc disk_error
add bx, 200h
inc eax
dec cx
jnz read
ret
.old_style:
; old style - CHS, function 2
; convert absolute sector in eax to cylinder-head-sector coordinates
; calculate sector
xor edx, edx
movzx ecx, [sectors]
div ecx
; sectors are counted from 1
inc dl
mov cl, dl ; low 6 bits of cl = sector number
; calculate head number
; shld edx, eax, 10h ; convert eax to dx:ax
push eax
pop ax
pop dx
div [heads]
mov dh, dl ; dh = head
mov ch, al ; ch = low 8 bits of cylinder
shl ah, 6
or cl, ah ; high 2 bits of cl = high 2 bits of cylinder
.patch2:
mov ax, 201h ; function 2, al=1 - number of sectors
mov dl, [boot_drive]
int 13h
jmp .end
 
disk_error:
mov si, disk_error_msg
call out_string
jmp $
 
answer db ?
db 13,10
has_lba db 0
 
disk_error_msg db 'Disk read error!',0
start_msg db 2,' KolibriOS bootloader, running on ',0
errfs_msg db 'unknown filesystem, cannot continue',0
fat16_msg db 'FAT12/FAT16 - unsupported',13,10,0
fat32_msg db 'FAT32',13,10,0
ntfs_msg db 'NTFS',13,10,0
error_msg db 'Error'
colon db ': ',0
mft_string db 'MFT',0
root_string db '\',0
noindex_string db '$INDEX_ROOT not found',0
invalid_read_request_string db 'cannot read attribute',0
nodata_string db '$DATA '
notfound_string db 'not found',0
directory_string db 'is a directory',0
notdir_string db 'not a directory',0
fragmented_string db 'too fragmented file',0
bad_cluster_string db 'bad cluster',0
exmem_string db 'extended memory error',0
 
load_question db 'Load KolibriOS? [y/n]: ',0
 
repeat 0D256h - $
db 1
end repeat
 
start:
xor ax, ax
mov ds, ax
mov es, ax
; our stack is 4Kb-2b!!! (0xFFE)
mov ss, ax
mov esp, 0FFFEh
cld
sti
; calculate drive size
mov dl, [boot_drive]
mov ah, 8 ; 8 = get drive parameters
int 13h
; now: CF is set on error;
; ch = low 8 bits of maximum cylinder number
; cl : low 6 bits makes maximum sector number, high 2 bits are high 2 bits of maximum cylinder number
; dh = maximum head number
jnc @f
mov cx, -1
mov dh, cl
@@:
movzx ax, dh
inc ax
; ax = number of heads
mov [heads], ax
mov dl, cl
and dx, 3Fh
; dx = number of sectors
; (note that sectors are counted from 1, and maximum sector number = number of sectors)
mov [sectors], dx
mul dx
xchg cl, ch
shr ch, 6
inc cx
; cx = number of cylinders
mov [cyls], cx
mul cx
mov word [drive_size], ax
mov word [drive_size+2], dx
; this drive supports LBA?
mov dl, [boot_drive]
mov ah, 41h
mov bx, 55AAh
int 13h
jc .no_lba
cmp bx, 0AA55h
jnz .no_lba
test cl, 1
jz .no_lba
inc [has_lba]
.no_lba:
; say hi to user
mov si, start_msg
call out_string
mov eax, [partition_start]
cmp eax, -1
jnz @f
; now read first sector to determine file system type
; first sector of disk is MBR sector
xor eax, eax
mov cx, 1
mov bx, 500h
call read
mov eax, [6C6h] ; first disk
mov [partition_start], eax
@@:
mov cx, 1
mov bx, 500h
call read
movzx ax, byte [50Dh]
mov [sect_per_clust], ax
; determine file system
cmp dword [536h], 'FAT1'
jz fat1x
cmp dword [552h], 'FAT3'
jz fat32
cmp dword [503h], 'NTFS'
jz ntfs
; mov si, errfs_msg ; already is
call out_string
jmp $
fat1x:
mov si, fat16_msg
call out_string
jmp $
fat32:
mov si, fat32_msg
call out_string
movzx eax, word [50Bh] ; bytes_per_sect
movzx ebx, byte [50Dh] ; sects_per_clust
mul ebx
mov [cluster_size], eax
movzx ebx, word [50Eh] ; reserved_sect
mov [fat_start], ebx
movzx eax, byte [510h] ; num_fats
mul dword [524h] ; sect_fat
add eax, ebx
; cluster 2 begins from sector eax
movzx ebx, byte [50Dh] ; sects_per_clust
sub eax, ebx
sub eax, ebx
mov [data_start], eax
; parse image name
mov eax, [52Ch] ; root_cluster
mov [cur_obj], root_string
.parsedir:
push ax
mov si, [imgnameofs]
push si
@@:
lodsb
cmp al, '\'
jz @f
cmp al, 0
jnz @b
@@:
xchg ax, [esp+2]
mov byte [si-1], 0
mov [imgnameofs], si
call fat32_parse_dir
pop cx
test cl, cl
jz .end
test byte [di+0Bh], 10h
mov si, notdir_string
jz find_error_si
jmp .parsedir
.end:
test byte [di+0Bh], 10h
mov si, directory_string
jnz find_error_si
; parse FAT chunk
; runlist at 2000:0000
mov di, 5
push 2000h
pop es
mov byte [es:di-5], 1 ; of course, non-resident
mov dword [es:di-4], 1
stosd
.parsefat:
push es
push ds
pop es
call next_cluster
pop es
jnc .done
mov ecx, [es:di-8]
add ecx, [es:di-4]
cmp eax, ecx
jz .contc
mov dword [es:di], 1
scasd
stosd
jmp .parsefat
.contc:
inc dword [es:di-8]
jmp .parsefat
.done:
xor eax, eax
stosd
jmp read_img_file
 
ntfs:
mov si, ntfs_msg
call out_string
movzx eax, word [50Bh] ; bpb_bytes_per_sect
push eax
movzx ebx, byte [50Dh] ; bpb_sects_per_clust
mul ebx
mov [cluster_size], eax
mov [data_start], 0
mov ecx, [540h] ; frs_size
cmp cl, 0
jg .1
neg cl
xor eax, eax
inc eax
shl eax, cl
jmp .2
.1:
mul ecx
.2:
mov [frs_size], eax
pop ebx
xor edx, edx
div ebx
mov [frs_sectors], ax
; read first MFT record - description of MFT itself
mov [cur_obj], mft_string
movzx eax, byte [50Dh] ; bpb_sects_per_clust
mul dword [530h] ; mft_cluster
mov cx, [frs_sectors]
mov bx, 4000h
mov di, bx
push bx
call relative_read
call restore_usa
; scan for unnamed $DATA attribute
pop di
mov ax, 80h ; $DATA
mov bx, 700h
call load_attr
mov si, nodata_string
jc find_error_si
mov [free], bx
; load menuet.img
; parse image name
mov eax, 5 ; root cluster
mov [cur_obj], root_string
.parsedir:
push ax
mov si, [imgnameofs]
push si
@@:
lodsb
cmp al, '\'
jz @f
cmp al, 0
jnz @b
@@:
xchg ax, [esp+2]
mov byte [si-1], 0
mov [imgnameofs], si
call ntfs_parse_dir
pop cx
test cl, cl
jnz .parsedir
read_img_file:
xor si, si
push es
pop fs
; yes! Now read file to 0x100000
lods byte [fs:si]
cmp al, 0 ; assume nonresident attr
mov si, invalid_read_request_string
jz find_error_si
mov si, 1
xor edi, edi
; read buffer to 1000:0000 and move it to extended memory
push 1000h
pop es
xor bx, bx
.img_read_block:
lods dword [fs:si] ; eax=length
xchg eax, ecx
jecxz .img_read_done
lods dword [fs:si] ; eax=disk cluster
.img_read_cluster:
pushad
; read part of file
movzx ecx, byte [50Dh]
mul ecx
add eax, [data_start]
call relative_read
; move it to extended memory
mov ah, 87h
mov ecx, [cluster_size]
push ecx
shr cx, 1
mov si, movedesc
push es
push ds
pop es
int 15h
pop es
test ah, ah
mov si, exmem_string
jnz find_error_si
pop ecx
add [dest_addr], ecx
popad
inc eax
loop .img_read_cluster
jmp .img_read_block
.img_read_done:
; menuet.img loaded; now load kernel.mnt
load_kernel:
push ds
pop es
mov [cur_obj], kernel_mnt_name
; read boot sector
xor eax, eax
mov bx, 500h
mov cx, 1
call read_img
; init vars
mov ax, [50Eh] ; reserved_sect
add ax, [51Ch] ; hidden
mov word [fat_start], ax
xchg ax, bx
movzx ax, byte [510h] ; num_fats
mul word [516h] ; fat_length
add ax, bx
; read root dir
mov bx, 700h
mov cx, [511h] ; dir_entries
add cx, 0Fh
shr cx, 4
call read_img
add ax, cx
mov [img_data_start], ax
shl cx, 9
mov di, bx
add bx, cx
mov byte [bx], 0
.scan_loop:
cmp byte [di], 0
mov si, notfound_string
jz find_error_si
mov si, kernel_mnt_name
call fat_compare_name
jz .found
and di, not 1Fh
add di, 20h
jmp .scan_loop
.found:
and di, not 1Fh
mov si, directory_string
test byte [di+0Bh], 10h
jnz find_error_si
; found, now load it to 1000h:0000h
mov ax, [di+1Ah]
; first cluster of kernel.mnt in ax
; translate it to sector on disk in menuet.img
push ax
dec ax
dec ax
movzx cx, byte [50Dh]
mul cx
add ax, [img_data_start]
; now ax is sector in menuet.img
mov [kernel_mnt_in_img], ax
div [sect_per_clust]
; now ax is cluster in menuet.img and
; dx is offset from the beginning of cluster
movzx eax, ax
push 2000h
pop ds
mov si, 1
.scani:
sub eax, [si]
jb .scanidone
; sanity check
cmp dword [si], 0
push invalid_read_request_string
jz find_error_sp
pop cx
; next chunk
add si, 8
jmp .scani
.scanidone:
add eax, [si] ; undo last subtract
add eax, [si+4] ; get cluster
push 0
pop ds
movzx ecx, [sect_per_clust]
push dx
mul ecx ; get sector
pop dx
movzx edx, dx
add eax, edx
add eax, [data_start]
mov [kernel_mnt_1st], eax
pop ax
push 1000h
pop es
.read_loop:
push ax
xor bx, bx
call img_read_cluster
shl cx, 9-4
mov ax, es
add ax, cx
mov es, ax
pop ax
call img_next_cluster
jc .read_loop
mov ax, 'KL'
mov si, loader_block
jmp 1000h:0000h
 
img_next_cluster:
mov bx, 700h
push ax
shr ax, 1
add ax, [esp]
mov dx, ax
shr ax, 9
add ax, word [fat_start]
mov cx, 2
push es
push ds
pop es
call read_img
pop es
and dx, 1FFh
add bx, dx
mov ax, [bx]
pop cx
test cx, 1
jz .1
shr ax, 4
.1:
and ax, 0FFFh
mov si, bad_cluster_string
cmp ax, 0FF7h
jz find_error_si
ret
img_read_cluster:
dec ax
dec ax
movzx cx, byte [50Dh] ; sects_per_clust
mul cx
add ax, [img_data_start]
movzx eax, ax
; call read_img
; ret
read_img:
; in: ax = sector, es:bx->buffer, cx=length in sectors
pushad
movzx ebx, bx
mov si, movedesc
shl eax, 9
add eax, 93100000h
mov dword [si+sou_addr-movedesc], eax
mov eax, 9300000h
mov ax, es
shl eax, 4
add eax, ebx
mov [si+dest_addr-movedesc], eax
mov ah, 87h
shl cx, 8 ; mul 200h/2
push es
push 0
pop es
int 15h
pop es
cmp ah, 0
mov si, exmem_string
jnz find_error_si
popad
ret
 
movedesc:
times 16 db 0
; source
dw 0xFFFF ; segment length
sou_addr dw 0000h ; linear address
db 1 ; linear address
db 93h ; access rights
dw 0
; destination
dw 0xFFFF ; segment length
dest_addr dd 93100000h ; high byte contains access rights
; three low bytes contains linear address (updated when reading)
dw 0
times 32 db 0
 
find_error_si:
push si
find_error_sp:
mov si, error_msg
call out_string
mov si, [cur_obj]
call out_string
mov si, colon
call out_string
pop si
call out_string
jmp $
 
file_not_found:
mov si, [esp+2]
mov [cur_obj], si
push notfound_string
jmp find_error_sp
 
include 'fat32.inc'
include 'ntfs.inc'
 
write1st:
; callback from kernel.mnt
; write first sector of kernel.mnt from 1000:0000 back to disk
push cs
pop ds
push cs
pop es
; sanity check
mov bx, 500h
mov si, bx
mov cx, 1
push cx
mov eax, [kernel_mnt_1st]
push eax
call relative_read
push 1000h
pop es
xor di, di
mov cx, 8
repz cmpsw
mov si, data_error_msg
jnz find_error_si
; ok, now write back to disk
or byte [read.patch1+2], 1
or byte [read.patch2+2], 1
xor bx, bx
pop eax
pop cx
call relative_read
and byte [read.patch1+1], not 1
and byte [read.patch2+2], not 2
; and to image in memory (probably this may be done by kernel.mnt itself?)
mov dword [sou_addr], 93010000h
movzx eax, [kernel_mnt_in_img]
shl eax, 9
add eax, 93100000h
mov dword [dest_addr], eax
mov si, movedesc
push ds
pop es
mov ah, 87h
mov cx, 100h
int 15h
cmp ah, 0
mov si, exmem_string
jnz find_error_si
retf
 
loader_block:
db 1 ; version
dw 1 ; flags - image is loaded
dw write1st ; offset
dw 0 ; segment
 
fat_cur_sector dd -1
 
data_error_msg db 'data error',0
 
; -----------------------------------------------
; ------------------ Settings -------------------
; -----------------------------------------------
 
; must be in lowercase, see ntfs_parse_dir.scan, fat32_parse_dir.scan
kernel_mnt_name db 'kernel.mnt',0
 
; will be initialized by installer
menuet_img_name rb 300
 
; uninitialized data follows
drive_size dd ? ; in sectors
heads dw ?
sectors dw ?
cyls dw ?
free dw ?
cur_obj dw ?
data_start dd ?
img_data_start dw ?
sect_per_clust dw ?
kernel_mnt_in_img dw ?
kernel_mnt_1st dd ?
; NTFS data
cluster_size dd ? ; in bytes
frs_size dd ? ; in bytes
frs_sectors dw ? ; in sectors
mft_data_attr dw ?
index_root dw ?
index_alloc dw ?
ofs dw ?
dir dw ?
; FAT32 data
fat_start dd ?
cur_cluster dd ?
/programs/hd_load/mtldr_install/mtldr_code/ntfs.inc
0,0 → 1,531
restore_usa:
; Update Sequence Array restore
mov bx, [di+4]
mov cx, [di+6]
inc bx
add bx, di
inc bx
add di, 1feh
dec cx
@@:
mov ax, [bx]
stosw
inc bx
inc bx
add di, 1feh
loop @b
ret
 
find_attr:
; in: di->file record, ax=attribute
; out: di->attribute or di=0 if not found
add di, [di+14h]
.1:
; attributes codes are formally dwords, but all they fit in word
cmp word [di], -1
jz .notfound
cmp word [di], ax
jnz .continue
; for $DATA attribute, scan only unnamed
cmp ax, 80h
jnz .found
cmp byte [di+9], 0
jz .found
.continue:
add di, [di+4]
jmp .1
.notfound:
xor di, di
.found:
ret
 
process_mcb_nonres:
; in: si->attribute, es:di->buffer
; out: di->buffer end
add si, [si+20h]
xor ebx, ebx
.loop:
lodsb
test al, al
jz .done
push invalid_read_request_string
movzx cx, al
shr cx, 4
jz find_error_sp
xchg ax, dx
and dx, 0Fh
jz find_error_sp
add si, cx
add si, dx
pop ax
push si
dec si
movsx eax, byte [si]
dec cx
jz .l1e
.l1:
dec si
shl eax, 8
mov al, [si]
loop .l1
.l1e:
xchg ebp, eax
dec si
movsx eax, byte [si]
mov cx, dx
dec cx
jz .l2e
.l2:
dec si
shl eax, 8
mov al, byte [si]
loop .l2
.l2e:
pop si
add ebx, ebp
; eax=length, ebx=disk block
stosd
mov eax, ebx
stosd
jmp .loop
.done:
xor eax, eax
stosd
ret
 
load_attr:
; in: ax=attribute, es:bx->buffer, di->base record
; out: bx->buffer end; CF set if not found
push di
push ax
mov byte [es:bx], 1
inc bx
push bx
mov [ofs], bx
; scan for attrubute
add di, [di+14h]
@@:
call find_attr.1
test di, di
jz .notfound1
cmp byte [di+8], 0
jnz .nonresident
jmp .resident
.aux_resident:
push di
popad
; resident attribute
.resident:
mov si, di
pop di
dec di
mov al, 0
stosb
mov ax, [si+10h]
stosw
xchg ax, cx
add si, [si+14h]
rep movsb
mov bx, di
pop ax
pop di
ret
.nonresident:
; nonresident attribute
cmp dword [di+10h], 0
jnz @b
; read start of data
mov si, di
pop di
call process_mcb_nonres
sub di, 4
push di
.notfound1:
; $ATTRIBUTE_LIST is always in base file record
cmp word [esp+2], 20h
jz .nofragmented
; scan for $ATTRIBUTE_LIST = 20h
mov di, [esp+4]
mov ax, 20h
call find_attr
test di, di
jz .nofragmented
; load $ATTRIBUTE_LIST itself
push es
mov bx, 0C000h
mov di, [esp+6]
push bx
push [ofs]
push ds
pop es
call load_attr
pop [ofs]
pop si
mov bx, 8000h
push bx
push si
call read_attr_full
pop si
pop bx
add dx, bx
mov ax, [esp+4]
pop es
.1:
cmp [bx], ax
jnz .continue1
; only unnamed $DATA attributes!
cmp ax, 80h
jnz @f
cmp byte [bx+6], 0
jnz .continue1
@@:
cmp dword [bx+10h], 0
jz .continue1
cmp dword [bx+8], 0
jnz @f
push ax
mov ax, [esp+2]
cmp ax, [ofs]
pop ax
jnz .continue1
@@:
pushad
mov eax, [bx+10h]
mov bx, dx
push [ofs]
push es
push ds
pop es
call read_file_record
pop es
pop [ofs]
popad
pushad
pop di
mov di, dx
add di, [di+14h]
.2:
call find_attr.1
cmp byte [di+8], 0
jz .aux_resident
mov eax, [bx+8]
cmp eax, [di+10h]
jnz .2
mov si, di
mov di, [esp+1Eh]
call process_mcb_nonres
sub di, 4
mov [esp+1Eh], di
push di
popad
.continue1:
add bx, [bx+4]
cmp bx, dx
jb .1
.nofragmented:
pop bx
pop ax
pop di
cmp bx, [ofs]
jnz @f
dec bx
stc
ret
@@:
add bx, 4
ret
 
read_attr_full:
; in: si->decoded attribute data, bx->buffer
; out: edx=length in bytes
lodsb
cmp al, 0
jnz .nonresident
; resident
lodsw
movzx edx, ax
xchg ax, cx
mov di, bx
rep movsb
ret
.nonresident:
; nonresident :-)
xor edx, edx
.loop:
lodsd
xchg ecx, eax
jecxz .loopend
lodsd
xchg edi, eax
; read ecx clusters from cluster edi to es:bx
.intloop:
push ecx
; read 1 cluster from physical cluster edi to es:bx
mov ecx, [cluster_size]
mov eax, edi
mul ecx
push bx
call relative_read
pop bx
pop ecx
inc edi
mov eax, [cluster_size]
add edx, eax
shr eax, 4
mov bp, es
add bp, ax
mov es, bp
loop .intloop
jmp .loop
.loopend:
mov es, cx
ret
 
read_file_record:
; in: eax=index of record, bx=buffer
mov si, 700h
mov ecx, [frs_size]
mul ecx
push bx
push [cur_obj]
mov [cur_obj], mft_string
call read_attr
pop [cur_obj]
pop di
call restore_usa
ret
read_attr:
; in: edx:eax=offset in bytes, ecx=size in bytes, bx=buffer, si=attribute
push invalid_read_request_string
cmp byte [si], 0
jnz .nonresident
test edx, edx
jnz find_error_sp
cmp eax, 10000h
jae find_error_sp
cmp ecx, 10000h
jae find_error_sp
cmp ax, [si+2]
jae find_error_sp
cmp cx, [si+2]
ja find_error_sp
add si, 3
add si, ax
mov di, bx
rep movsb
pop ax
ret
.nonresident:
mov edi, [cluster_size]
div edi
mov [ofs], dx
add cx, dx
push eax
xchg eax, ecx
xor edx, edx
dec eax
div edi
inc eax
xchg eax, ecx
pop eax
add si, 1
xor edx, edx
push bx
; eax=offset in clusters, ecx=size in clusters
.scan:
mov ebx, [si]
test ebx, ebx
jz .notfound
add edx, ebx
add si, 8
cmp eax, edx
jae .scan
mov edi, [si-4]
; now edx=end of block, ebx=length of block, edi=start of block on disk
; eax=required offset, ecx=required length
push edx
push edi
sub edx, eax
add edi, ebx
sub edi, edx
cmp edx, ecx
jb @f
mov edx, ecx
@@:
; read (edx) clusters from (edi=disk offset in clusters) to ([esp+8])
cmp [ofs], 0
jnz .ofs_read
.cont:
pushad
movzx ebx, byte [50Dh]
; xchg eax, edx
; mul ebx
xchg ax, dx
mul bx
xchg cx, ax
xchg eax, edi
mul ebx
mov bx, [esp+8+20h]
call relative_read
mov [esp+8+20h], bx
popad
.cont2:
add eax, edx
sub ecx, edx
.cont3:
pop edi
pop edx
jnz .scan
pop bx
pop ax
ret
.ofs_read:
push ecx
movzx ecx, byte [50Dh] ; bpb_sects_per_clust
mov eax, edi
push edx
mul ecx
push 1000h
pop es
xor bx, bx
call relative_read
mov cx, bx
push si
push di
mov si, [ofs]
mov di, [esp+8+12]
sub cx, si
push ds
push es
pop ds
pop es
rep movsb
mov [esp+8+12], di
push es
pop ds
pop di
pop si
pop edx
pop ecx
inc edi
mov [ofs], 0
inc eax
dec ecx
jz .cont3
dec edx
jnz .cont
jmp .cont2
.notfound:
mov si, invalid_read_request_string
jmp find_error_si
 
ntfs_parse_dir:
; in: eax=directory iRecord, [word sp+2]=filename
; out: si=$DATA attribute of file
mov bx, [free]
mov [dir], bx
push bx
call read_file_record
mov ax, word [frs_size]
add [free], ax
pop di
; find attributes $INDEX_ROOT, $INDEX_ALLOCATION, $BITMAP
mov ax, 90h ; $INDEX_ROOT
push di
mov bx, [free]
mov [index_root], bx
call load_attr
mov si, noindex_string
jc find_error_si
mov [free], bx
pop di
mov ax, 0A0h ; $INDEX_ALLOCATION
mov bx, [free]
mov [index_alloc], bx
call load_attr
jnc @f
mov [index_alloc], 0
@@:
mov [free], bx
; search for entry
mov si, [index_root]
mov bx, [free]
call read_attr_full
mov ebp, [bx+8] ; subnode_size
add bx, 10h
.scan_record:
add bx, [bx]
.scan:
test byte [bx+0Ch], 2
jnz .not_found
mov si, [esp+2]
movzx cx, byte [bx+50h] ; namelen
lea di, [bx+52h] ; name
xor ax, ax
@@:
lodsb
cmp al, 'a'
jb .notletter
cmp al, 'z'
ja .notletter
or byte [di], 20h
.notletter:
scasw
loopz @b
jb .not_found
ja @f
cmp byte [esi], 0
jz .file_found
@@:
add bx, [bx+8]
jmp .scan
.not_found:
test byte [bx+0Ch], 1
jz file_not_found
cmp [index_alloc], 0
jz file_not_found
add bx, [bx+8]
mov eax, [bx-8]
mul [cluster_size]
mov si, [index_alloc]
mov ecx, ebp
mov bx, [free]
call read_attr
mov di, [free]
call restore_usa
mov bx, [free]
add bx, 18h
jmp .scan_record
.file_found:
mov si, [esp+2]
mov [cur_obj], si
cmp byte [esp+4], 0
jz .need_file
mov si, notdir_string
test byte [bx+48h+3], 10h
jz find_error_si
mov eax, [bx]
mov bx, [dir]
mov [free], bx
ret 2
.need_file:
mov si, directory_string
test byte [bx+48h+3], 10h ; directory?
jnz find_error_si
; read entry
mov eax, [bx]
mov bx, [dir]
mov [free], bx
mov bx, 4000h
push bx
call read_file_record
pop di
mov ax, 80h
push 2000h
pop es
xor bx, bx
call load_attr
mov si, nodata_string
jz find_error_si
mov [free], bx
ret 2