/kernel/tags/kolibri0.6.5.0/fs/fat12.inc |
---|
0,0 → 1,2789 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; FAT12.INC ;; |
;; (C) 2005 Mario79, License: GPL ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
n_sector dd 0 ; temporary save for sector value |
flp_status dd 0 |
clust_tmp_flp dd 0 ; used by analyze_directory and analyze_directory_to_write |
path_pointer_flp dd 0 |
pointer_file_name_flp dd 0 |
save_root_flag db 0 |
save_flag db 0 |
root_read db 0 ; 0-necessary to load root, 1-not to load root |
flp_fat db 0 ; 0-necessary to load fat, 1-not to load fat |
flp_number db 0 ; 1- Floppy A, 2-Floppy B |
old_track db 0 ; old value track |
flp_label rb 15 ; Label and ID of inserted floppy disk |
reserve_flp: |
cli |
cmp [flp_status],0 |
je reserve_flp_ok |
sti |
call change_task |
jmp reserve_flp |
reserve_flp_ok: |
push eax |
mov eax,[0x3000] |
shl eax,5 |
mov eax,[eax+0x3000+TASKDATA.pid] |
mov [flp_status],eax |
pop eax |
sti |
ret |
floppy_free_space: |
;--------------------------------------------- |
; |
; returns free space in edi |
; |
;--------------------------------------------- |
push eax ebx ecx |
call read_flp_fat |
cmp [FDC_Status],0 |
jne fdc_status_error_2 |
mov eax,0x282004 |
xor edi,edi |
mov ecx,2847 ;1448000/512 |
rdfs1_1: |
mov ebx,[eax] |
and ebx,4095 |
jne rdfs2_1 |
add edi,512 |
rdfs2_1: |
add eax,2 |
loop rdfs1_1 |
fdc_status_error_2: |
pop ecx ebx eax |
ret |
floppy_fileread: |
;---------------------------------------------------------------- |
; |
; fileread - sys floppy |
; |
; eax points to filename 11 chars - for root directory |
; ebx first wanted block ; 1+ ; if 0 then set to 1 |
; ecx number of blocks to read ; 1+ ; if 0 then set to 1 |
; edx mem location to return data |
; esi length of filename 12*X |
; edi pointer to path /fd/1/...... - for all files in nested directories |
; |
; ret ebx = size or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; 10 = access denied |
;-------------------------------------------------------------- |
mov [save_flag],0 |
mov [path_pointer_flp],edi |
cmp esi,0 ; return ramdisk root |
jne fr_noroot_1 |
cmp ebx,224/16 |
jbe fr_do_1 |
mov eax,5 |
mov ebx,0 |
mov [flp_status],0 |
ret |
fr_do_1: |
push ebx ecx edx |
call read_flp_root |
pop edx ecx ebx |
cmp [FDC_Status],0 |
jne fdc_status_error_1 |
mov edi,edx |
dec ebx |
shl ebx,9 |
mov esi,0x8000 |
add esi,ebx |
shl ecx,9 |
cld |
rep movsb |
mov eax,0 ; ok read |
mov ebx,0 |
mov [flp_status],0 |
ret |
fdc_status_error_1: |
mov [flp_status],0 |
mov eax,10 |
mov ebx,-1 |
ret |
fr_noroot_1: |
sub esp,32 |
call expand_filename |
frfloppy_1: |
cmp ebx,0 |
jne frfl5_1 |
mov ebx,1 |
frfl5_1: |
cmp ecx,0 |
jne frfl6_1 |
mov ecx,1 |
frfl6_1: |
dec ebx |
push eax |
push eax ebx ecx edx esi edi |
call read_flp_fat |
cmp [FDC_Status],0 |
jne fdc_status_error_3_1 |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],1 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
call SeekTrack |
mov dh,14 |
l.20_1: |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne fdc_status_error_3_1 |
mov dl,16 |
mov edi,0xD000 |
inc [FDD_Sector] |
l.21_1: |
mov esi,eax ;Name of file we want |
mov ecx,11 |
cld |
rep cmpsb ;Found the file? |
je fifound_1 ;Yes |
add ecx,21 |
add edi, ecx ;Advance to next entry |
dec dl |
cmp dl,0 |
jne l.21_1 |
dec dh |
cmp dh,0 |
jne l.20_1 |
fdc_status_error_3: |
mov eax,5 ; file not found ? |
mov ebx,-1 |
add esp,32+28 |
mov [flp_status],0 |
ret |
fdc_status_error_3_2: |
cmp [FDC_Status],0 |
je fdc_status_error_3 |
fdc_status_error_3_1: |
add esp,32+28 |
jmp fdc_status_error_1 |
fifound_1: |
mov eax,[path_pointer_flp] |
cmp [eax+36],byte 0 |
je fifound_2 |
add edi,0xf |
mov eax,[edi] |
and eax,65535 |
mov ebx,[path_pointer_flp] |
add ebx,36 |
call get_cluster_of_a_path_flp |
jc fdc_status_error_3_2 |
mov ebx,[ebx-11+28] ;file size |
mov [esp+20],ebx |
mov [esp+24],ebx |
jmp fifound_3 |
fifound_2: |
mov ebx,[edi-11+28] ;file size |
mov [esp+20],ebx |
mov [esp+24],ebx |
add edi,0xf |
mov eax,[edi] |
fifound_3: |
and eax,65535 |
mov [n_sector],eax ;eax=cluster |
frnew_1: |
add eax,31 ;bootsector+2*fat+filenames |
cmp [esp+16],dword 0 ; wanted cluster ? |
jne frfl7_1 |
call read_chs_sector |
cmp [FDC_Status],0 |
jne fdc_status_error_5 |
mov edi,[esp+8] |
call give_back_application_data_1 |
add [esp+8],dword 512 |
dec dword [esp+12] ; last wanted cluster ? |
cmp [esp+12],dword 0 |
je frnoread_1 |
jmp frfl8_1 |
frfl7_1: |
dec dword [esp+16] |
frfl8_1: |
mov edi,[n_sector] |
shl edi,1 ;find next cluster from FAT |
add edi,0x282000 |
mov eax,[edi] |
and eax,4095 |
mov edi,eax |
mov [n_sector],edi |
cmp edi,4095 ;eof - cluster |
jz frnoread2_1 |
cmp [esp+24],dword 512 ;eof - size |
jb frnoread_1 |
sub [esp+24],dword 512 |
jmp frnew_1 |
read_chs_sector: |
call calculate_chs |
call ReadSectWithRetr |
ret |
frnoread2_1: |
cmp [esp+16],dword 0 ; eof without read ? |
je frnoread_1 |
mov [fdc_irq_func],fdc_null |
pop edi esi edx ecx |
add esp,4 |
pop ebx ; ebx <- eax : size of file |
add esp,36 |
mov eax,6 ; end of file |
mov [flp_status],0 |
ret |
frnoread_1: |
pop edi esi edx ecx |
add esp,4 |
pop ebx ; ebx <- eax : size of file |
add esp,36 |
mov eax,0 |
mov [flp_status],0 |
ret |
fdc_status_error_5: |
pop edi esi edx ecx |
add esp,4 |
pop ebx ; ebx <- eax : size of file |
add esp,36 |
jmp fdc_status_error_1 |
read_flp_root: |
pusha |
call check_label |
cmp [FDC_Status],0 |
jne unnecessary_root_read |
cmp [root_read],1 |
je unnecessary_root_read |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],1 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
mov edi,0x8000 |
call SeekTrack |
read_flp_root_1: |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne unnecessary_root_read |
push edi |
call give_back_application_data_1 |
pop edi |
add edi,512 |
inc [FDD_Sector] |
cmp [FDD_Sector],16 |
jne read_flp_root_1 |
mov [root_read],1 |
unnecessary_root_read: |
popa |
ret |
read_flp_fat: |
pusha |
call check_label |
cmp [FDC_Status],0 |
jne unnecessary_flp_fat |
cmp [flp_fat],1 |
je unnecessary_flp_fat |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],0 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
mov edi,0x8000 |
call SeekTrack |
read_flp_fat_1: |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne unnecessary_flp_fat |
push edi |
call give_back_application_data_1 |
pop edi |
add edi,512 |
inc [FDD_Sector] |
cmp [FDD_Sector],19 |
jne read_flp_fat_1 |
mov [FDD_Sector],1 |
mov [FDD_Head],1 |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne unnecessary_flp_fat |
call give_back_application_data_1 |
call calculatefatchain_flp |
mov [root_read],0 |
mov [flp_fat],1 |
unnecessary_flp_fat: |
popa |
ret |
calculatefatchain_flp: |
pushad |
mov esi,0x8000 |
mov edi,0x282000 |
fcnew_1: |
mov eax,dword [esi] |
mov ebx,dword [esi+4] |
mov ecx,dword [esi+8] |
mov edx,ecx |
shr edx,4 ;8 ok |
shr dx,4 ;7 ok |
xor ch,ch |
shld ecx,ebx,20 ;6 ok |
shr cx,4 ;5 ok |
shld ebx,eax,12 |
and ebx,0x0fffffff ;4 ok |
shr bx,4 ;3 ok |
shl eax,4 |
and eax,0x0fffffff ;2 ok |
shr ax,4 ;1 ok |
mov dword [edi],eax |
add edi,4 |
mov dword [edi],ebx |
add edi,4 |
mov dword [edi],ecx |
add edi,4 |
mov dword [edi],edx |
add edi,4 |
add esi,12 |
cmp edi,0x282000+2856*2 ;2849 clusters |
jnz fcnew_1 |
popad |
ret |
check_label: |
pushad |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],0 ; Ñòîðîíà |
mov [FDD_Sector],1 ; Ñåêòîð |
call SetUserInterrupts |
call FDDMotorON |
call RecalibrateFDD |
cmp [FDC_Status],0 |
jne fdc_status_error |
call SeekTrack |
cmp [FDC_Status],0 |
jne fdc_status_error |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne fdc_status_error |
mov esi,flp_label |
mov edi,0xD000+39 |
mov ecx,15 |
cld |
rep cmpsb |
je same_label |
mov [root_read],0 |
mov [flp_fat],0 |
same_label: |
mov esi,0xD000+39 |
mov edi,flp_label |
mov ecx,15 |
cld |
rep movsb |
popad |
ret |
fdc_status_error: |
popad |
ret |
save_flp_root: |
pusha |
call check_label |
cmp [FDC_Status],0 |
jne unnecessary_root_save |
cmp [root_read],0 |
je unnecessary_root_save |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],1 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
mov esi,0x8000 |
call SeekTrack |
save_flp_root_1: |
push esi |
call take_data_from_application_1 |
pop esi |
add esi,512 |
call WriteSectWithRetr |
cmp [FDC_Status],0 |
jne unnecessary_root_save |
inc [FDD_Sector] |
cmp [FDD_Sector],16 |
jne save_flp_root_1 |
unnecessary_root_save: |
mov [fdc_irq_func],fdc_null |
popa |
ret |
save_flp_fat: |
pusha |
call check_label |
cmp [FDC_Status],0 |
jne unnecessary_flp_fat_save |
cmp [flp_fat],0 |
je unnecessary_flp_fat_save |
call restorefatchain_flp |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],0 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
mov esi,0x8000 |
call SeekTrack |
save_flp_fat_1: |
push esi |
call take_data_from_application_1 |
pop esi |
add esi,512 |
call WriteSectWithRetr |
cmp [FDC_Status],0 |
jne unnecessary_flp_fat_save |
inc [FDD_Sector] |
cmp [FDD_Sector],19 |
jne save_flp_fat_1 |
mov [FDD_Sector],1 |
mov [FDD_Head],1 |
call take_data_from_application_1 |
call WriteSectWithRetr |
cmp [FDC_Status],0 |
jne unnecessary_flp_fat_save |
mov [root_read],0 |
unnecessary_flp_fat_save: |
mov [fdc_irq_func],fdc_null |
popa |
ret |
restorefatchain_flp: ; restore fat chain |
pushad |
mov esi,0x282000 |
mov edi,0x8000 |
fcnew2_1: |
mov eax,dword [esi] |
mov ebx,dword [esi+4] |
shl ax,4 |
shl eax,4 |
shl bx,4 |
shr ebx,4 |
shrd eax,ebx,8 |
shr ebx,8 |
mov dword [edi],eax |
add edi,4 |
mov word [edi],bx |
add edi,2 |
add esi,8 |
cmp edi,0x8000+0x1200 ;4274 bytes - all used FAT |
jb fcnew2_1 |
mov esi,0x8000 ; duplicate fat chain |
mov edi,0x8000+0x1200 |
mov ecx,0x1200/4 |
cld |
rep movsd |
popad |
ret |
floppy_filedelete: |
;-------------------------------------------- |
; |
; filedelete - sys floppy |
; in: |
; eax - filename 11 chars - for root directory |
; edi pointer to path /fd/1/...... - for all files in nested directories |
; |
; out: |
; eax - 0 = successful, 1 = file not found, 10 = access denied |
; |
;-------------------------------------------- |
mov [path_pointer_flp],edi |
mov [save_flag],0 |
mov ebp,1 ; file not found as default |
filedelete_newtry_1: |
sub esp,32 |
call expand_filename |
push eax ebx ecx edx esi edi |
call read_flp_fat |
cmp [FDC_Status],0 |
jne frnoreadd_1 |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],1 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
call SeekTrack |
mov dh,14 |
l.20_2: |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne fdc_status_error_4 |
mov dl,16 |
mov edi,0xD000 |
inc [FDD_Sector] |
l.21_2: |
mov esi,eax ;Name of file we want |
mov ecx,11 |
cld |
rep cmpsb ;Found the file? |
je fifoundd_1 ;Yes |
add ecx,21 |
add edi, ecx ;Advance to next entry |
dec dl |
jne l.21_2 |
dec dh |
jne l.20_2 |
jmp frnoreadd_1 |
fdc_status_error_4: |
pop edi esi edx ecx ebx eax |
add esp,32 |
jmp fdc_status_error_1 |
fifoundd_1: |
mov eax,[path_pointer_flp] |
cmp [eax+36],byte 0 |
je fifoundd_2 |
movzx eax, word [edi+0xf] |
mov ebx,[path_pointer_flp] |
add ebx,36 |
call get_cluster_of_a_path_flp |
jc frnoreadd_1_1 |
mov edi,ebx |
add edi,11 |
jmp fifoundd_2_1 |
fifoundd_2: |
dec [FDD_Sector] |
fifoundd_2_1: |
mov [edi-11],byte 0xE5 ;mark filename deleted |
movzx edi, word [edi+0xf] ;edi = cluster |
frnewd_1: |
shl edi,1 ;find next cluster from FAT |
add edi,0x282000 |
mov eax,[edi] |
mov [edi],word 0x0 ;clear fat chain cluster |
and eax,4095 |
mov edi,eax |
cmp edi,dword 4095 ;last cluster ? |
jz frnoreadd2_1 |
jmp frnewd_1 |
frnoreadd2_1: |
call WriteSectWithRetr |
cmp [FDC_Status],0 |
jne fdc_status_error_4 |
call save_flp_fat |
cmp [FDC_Status],0 |
jne fdc_status_error_4 |
; pop edi esi edx ecx ebx eax |
; add esp,32 |
mov ebp,0 ; file found |
; jmp filedelete_newtry_1 |
jmp frnoreadd_1 |
frnoreadd_1_1: |
cmp [FDC_Status],0 |
jne fdc_status_error_4 |
frnoreadd_1: |
pop edi esi edx ecx ebx eax |
add esp,32 |
mov eax,ebp |
ret |
floppy_filesave: |
;---------------------------------------------------------- |
; |
; filesave - sys floppy |
; |
; eax ; pointer to file name 11 chars - for root directory |
; ebx ; buffer |
; ecx ; count to write in bytes |
; edx ; 0 create new , 1 append |
; edi pointer to path /fd/1/...... - for all files in nested directories |
; |
; output : eax = 0 - ok |
; 5 - file not found / directory not found |
; 8 - disk full |
; 10 - access denied |
;----------------------------------------------------------- |
mov [path_pointer_flp],edi |
sub esp,32 |
call expand_filename |
cmp edx,0 |
jnz fsdel_1 |
pusha |
call floppy_filedelete |
cmp [FDC_Status],0 |
jne fdc_status_error_6 |
popa |
mov [save_flag],1 |
fsdel_1: |
call floppy_free_space |
cmp [FDC_Status],0 |
jne fdc_status_error_6 |
cmp ecx,edi |
jb rd_do_save_1 |
add esp,32 |
mov eax,8 ; not enough free space |
mov [flp_status],0 |
ret |
fdc_status_error_6: |
popa |
add esp,32 |
jmp fdc_status_error_1 |
rd_do_save_1: |
push eax ebx ecx edx esi edi |
call read_flp_fat |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
push eax |
mov eax,[path_pointer_flp] |
cmp [eax+36],byte 0 |
jne fifoundds_2 |
pop eax |
mov [save_root_flag],1 |
call read_flp_root |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
mov edi,0x8000 ;Point at directory |
mov edx,224 +1 |
; find an empty spot for filename in the root dir |
l20ds_1: |
sub edx,1 |
jz frnoreadds_1 |
l21ds_1: |
cmp [edi],byte 0xE5 |
jz fifoundds_1 |
cmp [edi],byte 0x0 |
jz fifoundds_1 |
add edi,32 ; Advance to next entry |
jmp l20ds_1 |
fifoundds_2: |
pop eax |
mov [save_root_flag],0 |
mov [FDD_Track],0 ; Öèëèíäð |
mov [FDD_Head],1 ; Ñòîðîíà |
mov [FDD_Sector],2 ; Ñåêòîð |
call SeekTrack |
mov dh,14 |
l.20_3: |
call ReadSectWithRetr |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
mov dl,16 |
mov edi,0xD000 |
inc [FDD_Sector] |
l.21_3: |
mov esi,eax ;Name of file we want |
mov ecx,11 |
cld |
rep cmpsb ;Found the file? |
je fifoundds_3 ;Yes |
add ecx,21 |
add edi, ecx ;Advance to next entry |
dec dl |
jne l.21_3 |
dec dh |
jne l.20_3 |
fdc_status_error_8: |
pop edi esi edx ecx ebx eax |
mov eax,5 ; file not found ? |
mov ebx,-1 |
add esp,32 |
mov [flp_status],0 |
ret |
fifoundds_3: |
add edi,0xf |
mov eax,[edi] |
and eax,65535 |
mov ebx,[path_pointer_flp] |
add ebx,36 |
call get_cluster_of_a_path_flp |
jc fdc_status_error_7_1 |
found_directory_for_writing_flp: |
call analyze_directory_to_write_flp |
jc fdc_status_error_7_1 |
mov edi,ebx |
fifoundds_1: |
push edi ; move the filename to root dir |
mov esi,[esp+4+20] |
cmp [save_root_flag],0 |
jne fifoundds_4 |
mov esi,[pointer_file_name_flp] |
fifoundds_4: |
mov ecx,11 |
cld |
rep movsb |
pop edi |
mov edx,edi |
add edx,11+0xf ; edx <- cluster save position |
mov ebx,[esp+12] ; save file size |
mov [edi+28],ebx |
mov [edi+11],byte 0x20 ; attribute |
call get_date_for_file ; from FAT32.INC |
mov [edi+24],ax ; date |
mov [edi+18],ax ; date |
call get_time_for_file ; from FAT32.INC |
mov [edi+22],ax ; time |
xor ax,ax |
mov [edi+20],ax |
mov ebx,1 ; first cluster |
cmp [save_root_flag],0 |
jne frnewds_1 |
call frnewds_2 |
pusha |
call WriteSectWithRetr |
popa |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
jmp frnewds_3 |
frnewds_1: |
call frnewds_2 |
frnewds_3: |
pusha ; move save to floppy cluster |
add ebx,31 |
mov eax,ebx |
mov esi,[esp+32+16] |
call take_data_from_application_1 |
call save_chs_sector |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
popa |
mov eax,[esp+12] |
cmp eax,512 |
jb flnsa_1 |
sub eax,512 |
mov [esp+12],eax |
mov eax,[esp+16] |
add eax,512 |
mov [esp+16],eax |
jmp frnewds_1 |
frnewds_2: |
add ebx,1 |
mov edi,ebx ; find free cluster in FAT |
shl edi,1 |
add edi,0x282000 |
mov eax,[edi] |
and eax,4095 |
jnz frnewds_2 |
mov [edx],bx ; save next cluster pos. to prev cl. |
mov edx,edi ; next save pos abs mem add |
ret |
flnsa_1: |
mov [edi],word 4095 ; mark end of file - last cluster |
cmp [save_root_flag],1 |
jne flnsa_2 |
call save_flp_root |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
flnsa_2: |
call save_flp_fat |
cmp [FDC_Status],0 |
jne fdc_status_error_7 |
frnoreadds_1: |
pop edi esi edx ecx ebx eax |
add esp,32 |
mov eax,0 |
mov [flp_status],0 |
ret |
fdc_status_error_7_1: |
cmp [FDC_Status],0 |
je fdc_status_error_8 |
fdc_status_error_7: |
pop edi esi edx ecx ebx eax |
add esp,32 |
jmp fdc_status_error_1 |
save_chs_sector: |
call calculate_chs |
call WriteSectWithRetr |
ret |
calculate_chs: |
mov bl,[FDD_Track] |
mov [old_track],bl |
mov ebx,18 |
xor edx,edx |
div ebx |
inc edx |
mov [FDD_Sector],dl |
xor edx,edx |
mov ebx,2 |
div ebx |
mov [FDD_Track],al |
mov [FDD_Head],0 |
cmp edx,0 |
je no_head_2 |
inc [FDD_Head] |
no_head_2: |
mov dl,[old_track] |
cmp dl,[FDD_Track] |
je no_seek_track_1 |
call SeekTrack |
no_seek_track_1: |
ret |
get_cluster_of_a_path_flp: |
;--------------------------------------------------------- |
; input : EBX = pointer to a path string |
; (example: the path "/files/data/document" become |
; "files......data.......document...0" |
; '.' = space char |
; '0' = char(0) (ASCII=0) !!! ) |
; output : if (CARRY=1) -> ERROR in the PATH |
; if (CARRY=0) -> EAX=cluster |
;--------------------------------------------------------- |
push edx |
mov edx,ebx |
search_end_of_path_flp: |
cmp [save_flag],0 |
jne search_end_of_path_flp_1 |
cmp byte [edx],0 |
je found_end_of_path_flp |
jmp search_end_of_path_flp_2 |
search_end_of_path_flp_1: |
cmp byte [edx+12],0 |
je found_end_of_path_flp |
search_end_of_path_flp_2: |
inc edx ; '/' |
call analyze_directory_flp |
jc directory_not_found_flp |
mov eax,[ebx+20-2] ; read the HIGH 16bit cluster field |
mov ax,[ebx+26] ; read the LOW 16bit cluster field |
and eax,0xfff ;[fatMASK] |
add edx,11 ; 8+3 (name+extension) |
jmp search_end_of_path_flp |
found_end_of_path_flp: |
inc edx |
mov [pointer_file_name_flp],edx |
pop edx |
clc ; no errors |
ret |
directory_not_found_flp: |
pop edx |
stc ; errors occour |
ret |
analyze_directory_flp: |
;-------------------------------- |
; input : EAX = first cluster of the directory |
; EBX = pointer to filename |
; output : IF CARRY=0 EAX = sector where th file is found |
; EBX = pointer in buffer |
; [buffer .. buffer+511] |
; ECX,EDX,EDI,EDI not changed |
; IF CARRY=1 |
;-------------------------------- |
push ebx ;[esp+16] |
push ecx |
push edx |
push esi |
push edi |
adr56_flp: |
mov [clust_tmp_flp],eax |
add eax,31 |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status],0 |
jne not_found_file_analyze_flp |
mov ecx,512/32 |
mov ebx,0xD000 |
adr1_analyze_flp: |
mov esi,edx ;[esp+16] |
mov edi,ebx |
cld |
push ecx |
mov ecx,11 |
rep cmpsb |
pop ecx |
je found_file_analyze_flp |
add ebx,32 |
loop adr1_analyze_flp |
mov eax,[clust_tmp_flp] |
shl eax,1 ;find next cluster from FAT |
add eax,0x282000 |
mov eax,[eax] |
and eax,4095 |
cmp eax,0x0ff8 |
jb adr56_flp |
not_found_file_analyze_flp: |
pop edi |
pop esi |
pop edx |
pop ecx |
add esp,4 |
stc ;file not found |
ret |
found_file_analyze_flp: |
pop edi |
pop esi |
pop edx |
pop ecx |
add esp,4 |
clc ;file found |
ret |
analyze_directory_to_write_flp: |
;-------------------------------- |
; input : EAX = first cluster of the directory |
; output : IF CARRY=0 EAX = sector where the file is found |
; EBX = pointer in buffer |
; [buffer .. buffer+511] |
; ECX,EDX,EDI,EDI not changed |
; IF CARRY=1 |
;-------------------------------- |
push ecx |
push edx |
push esi |
adr561: |
mov [clust_tmp_flp],eax |
add eax,31 |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status],0 |
jne error_found_file_analyze1 |
mov ecx,512/32 |
mov ebx,0xD000 |
adr1_analyze1: |
cmp byte [ebx],0x00 |
je found_file_analyze1 |
cmp byte [ebx],0xe5 |
je found_file_analyze1 |
avanti: |
add ebx,32 |
loop adr1_analyze1 |
mov eax,[clust_tmp_flp] |
shl eax,1 ;find next cluster from FAT |
add eax,0x282000 |
mov eax,[eax] |
and eax,4095 |
cmp eax,0x0ff8 |
jb adr561 |
call get_free_FAT ;this block of code add a new cluster |
;for the directory because the directory |
;is full |
mov [edi],word 0x0fff |
mov eax,[clust_tmp_flp] |
shl eax,1 ;find next cluster from FAT |
add eax,0x282000 |
sub edi,0x282000 |
mov [eax],di |
pusha |
mov ecx,512/4 |
xor eax,eax |
mov edi,0xD000 |
cld |
rep stosd |
popa |
mov eax,edi |
add eax,31 |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status],0 |
jne error_found_file_analyze1 |
mov ebx,0xD000 |
found_file_analyze1: |
pop esi |
pop edx |
pop ecx |
clc ;file found |
ret |
error_found_file_analyze1: |
pop esi |
pop edx |
pop ecx |
stc |
ret |
get_free_FAT_flp: |
;------------------------------------------ |
; input : EAX = # cluster for start the searching |
; output : EAX = # first cluster found free |
;------------------------------------------- |
push ebx |
mov ebx,1 |
check_new_flp: |
add ebx,1 |
mov edi,ebx ; find free cluster in FAT |
shl edi,1 |
add edi,0x282000 |
mov eax,[edi] |
and eax,4095 |
cmp eax,0x0 |
jnz check_new_flp |
pop ebx |
ret |
; \begin{diamond} |
fat_find_lfn: |
; in: esi->name |
; [esp+4] = next |
; [esp+8] = first |
; [esp+C]... - possibly parameters for first and next |
; out: CF=1 - file not found |
; else CF=0, esi->next name component, edi->direntry |
pusha |
lea eax, [esp+0Ch+20h] |
call dword [eax-4] |
jc .reterr |
sub esp, 262*2 ; reserve place for LFN |
mov ebp, esp |
push 0 ; for fat_get_name: read ASCII name |
.l1: |
call fat_get_name |
jc .l2 |
call fat_compare_name |
jz .found |
.l2: |
lea eax, [esp+0Ch+20h+262*2+4] |
call dword [eax-8] |
jnc .l1 |
add esp, 262*2+4 |
.reterr: |
stc |
popa |
ret |
.found: |
add esp, 262*2+4 |
; if this is LFN entry, advance to true entry |
cmp byte [edi+11], 0xF |
jnz @f |
lea eax, [esp+0Ch+20h] |
call dword [eax-8] |
jc .reterr |
@@: |
add esp, 8 ; CF=0 |
push esi |
push edi |
popa |
ret |
uglobal |
; this is for delete support |
fd_prev_sector dd ? |
fd_prev_prev_sector dd ? |
endg |
flp_root_next: |
cmp edi, 0xD200-0x20 |
jae @f |
add edi, 0x20 |
ret ; CF=0 |
@@: |
; read next sector |
inc dword [eax] |
cmp dword [eax], 14 |
jae flp_root_first.readerr |
push [fd_prev_sector] |
pop [fd_prev_prev_sector] |
push eax |
mov eax, [eax] |
add eax, 19-1 |
mov [fd_prev_sector], eax |
pop eax |
flp_root_first: |
mov eax, [eax] |
pusha |
add eax, 19 |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .readerr |
mov edi, 0xD000 |
ret ; CF=0 |
.readerr: |
stc |
ret |
flp_rootmem_first: |
mov edi, 0x8000 |
clc |
ret |
flp_rootmem_next: |
add edi, 0x20 |
cmp edi, 0x8000+14*0x200 |
cmc |
flp_rootmem_next_write: |
flp_rootmem_begin_write: |
flp_rootmem_end_write: |
ret |
flp_rootmem_extend_dir: |
stc |
ret |
flp_notroot_next: |
cmp edi, 0xD200-0x20 |
jae flp_notroot_next_sector |
add edi, 0x20 |
ret ; CF=0 |
flp_notroot_next_sector: |
push ecx |
mov ecx, [eax] |
push [fd_prev_sector] |
pop [fd_prev_prev_sector] |
add ecx, 31 |
mov [fd_prev_sector], ecx |
mov ecx, [(ecx-31)*2+0x282000] |
and ecx, 0xFFF |
cmp ecx, 2849 |
jae flp_notroot_first.err2 |
mov [eax], ecx |
pop ecx |
flp_notroot_first: |
mov eax, [eax] |
cmp eax, 2 |
jb .err |
cmp eax, 2849 |
jae .err |
pusha |
add eax, 31 |
call read_chs_sector |
popa |
mov edi, 0xD000 |
cmp [FDC_Status], 0 |
jnz .err |
ret ; CF=0 |
.err2: |
pop ecx |
.err: |
stc |
ret |
flp_notroot_begin_write: |
pusha |
mov eax, [eax] |
add eax, 31 |
call read_chs_sector |
popa |
ret |
flp_notroot_end_write: |
pusha |
mov eax, [eax] |
add eax, 31 |
call save_chs_sector |
popa |
ret |
flp_notroot_next_write: |
cmp edi, 0xD200 |
jae @f |
ret |
@@: |
call flp_notroot_end_write |
jmp flp_notroot_next_sector |
flp_notroot_extend_dir: |
; find free cluster in FAT |
pusha |
xor eax, eax |
mov edi, 0x282000 |
mov ecx, 2849 |
repnz scasw |
jnz .notfound |
mov word [edi-2], 0xFFF ; mark as last cluster |
sub edi, 0x282000 |
shr edi, 1 |
dec edi |
mov eax, [esp+28] |
mov ecx, [eax] |
mov [0x282000+ecx*2], di |
mov [eax], edi |
xor eax, eax |
mov edi, 0xD000 |
mov ecx, 128 |
rep stosd |
popa |
call flp_notroot_end_write |
mov edi, 0xD000 |
clc |
ret |
.notfound: |
popa |
stc |
ret |
fd_find_lfn: |
; in: esi->name |
; out: CF=1 - file not found |
; else CF=0 and edi->direntry, eax=directory cluster (0 for root) |
push esi edi |
push 0 |
push flp_root_first |
push flp_root_next |
.loop: |
call fat_find_lfn |
jc .notfound |
cmp byte [esi], 0 |
jz .found |
test byte [edi+11], 10h |
jz .notfound |
movzx eax, word [edi+26] ; cluster |
mov [esp+8], eax |
mov dword [esp+4], flp_notroot_first |
mov dword [esp], flp_notroot_next |
jmp .loop |
.notfound: |
add esp, 12 |
pop edi esi |
stc |
ret |
.found: |
mov eax, [esp+8] |
add eax, 31 |
cmp dword [esp], flp_root_next |
jnz @f |
add eax, -31+19 |
@@: |
add esp, 16 ; CF=0 |
pop esi |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyRead - LFN variant for reading floppy |
; |
; 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 |
; |
;-------------------------------------------------------------- |
fs_FloppyRead: |
call read_flp_fat |
cmp byte [esi], 0 |
jnz @f |
or ebx, -1 |
mov eax, 10 ; access denied |
ret |
@@: |
push edi |
call fd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, 5 ; file not found |
ret |
.found: |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
mov eax, 6 ; EOF |
pop edi |
ret |
@@: |
mov ebx, [ebx] |
.l1: |
push ecx edx |
push 0 |
mov eax, [edi+28] |
sub eax, ebx |
jb .eof |
cmp eax, ecx |
jae @f |
mov ecx, eax |
mov byte [esp], 6 ; EOF |
@@: |
movzx edi, word [edi+26] |
.new: |
jecxz .done |
test edi, edi |
jz .eof |
cmp edi, 0xFF8 |
jae .eof |
sub ebx, 512 |
jae .skip |
lea eax, [edi+31] |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .err |
lea eax, [0xD000+ebx+512] |
neg ebx |
push ecx |
cmp ecx, ebx |
jbe @f |
mov ecx, ebx |
@@: |
mov ebx, edx |
call memmove |
add edx, ecx |
sub [esp], ecx |
pop ecx |
xor ebx, ebx |
.skip: |
movzx edi, word [edi*2+0x282000] |
jmp .new |
.done: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx ecx |
jmp .reteof |
.err: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
mov al, 11 |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyReadFolder - LFN variant for reading floppy folders |
; |
; 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 |
; |
;-------------------------------------------------------------- |
fs_FloppyReadFolder: |
call read_flp_fat |
push edi |
cmp byte [esi], 0 |
jz .root |
call fd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
test byte [edi+11], 0x10 ; do not allow read files |
jnz .found_dir |
pop edi |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
movzx eax, word [edi+26] |
add eax, 31 |
push 0 |
jmp .doit |
.root: |
mov eax, 19 |
push 14 |
.doit: |
push ecx ebp |
sub esp, 262*2 ; reserve space for LFN |
mov ebp, esp |
push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE names |
mov ebx, [ebx] |
; init header |
push eax ecx |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
pop ecx eax |
mov byte [edx], 1 ; version |
mov esi, edi ; esi points to BDFE |
.main_loop: |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .error |
mov edi, 0xD000 |
push eax |
.l1: |
call fat_get_name |
jc .l2 |
cmp byte [edi+11], 0xF |
jnz .do_bdfe |
add edi, 0x20 |
cmp edi, 0xD200 |
jb .do_bdfe |
pop eax |
inc eax |
dec byte [esp+262*2+12] |
jz .done |
jns @f |
; read next sector from FAT |
mov eax, [(eax-31-1)*2+0x282000] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
jae .done |
add eax, 31 |
mov byte [esp+262*2+12], 0 |
@@: |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .error |
mov edi, 0xD000 |
push eax |
.do_bdfe: |
inc dword [edx+8] ; new file found |
dec ebx |
jns .l2 |
dec ecx |
js .l2 |
inc dword [edx+4] ; new file block copied |
call fat_entry_to_bdfe |
.l2: |
add edi, 0x20 |
cmp edi, 0xD200 |
jb .l1 |
pop eax |
inc eax |
dec byte [esp+262*2+12] |
jz .done |
jns @f |
; read next sector from FAT |
mov eax, [(eax-31-1)*2+0x282000] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
jae .done |
add eax, 31 |
mov byte [esp+262*2+12], 0 |
@@: |
jmp .main_loop |
.error: |
add esp, 262*2+4 |
pop ebp ecx edi edi |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.done: |
add esp, 262*2+4 |
pop ebp |
mov ebx, [edx+4] |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
pop ecx edi edi |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyRewrite - LFN variant for writing sys floppy |
; |
; 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 |
; |
;-------------------------------------------------------------- |
@@: |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
fsfrfe2: |
popad |
fsfrfe: |
mov eax, 11 |
xor ebx, ebx |
ret |
fs_FloppyCreateFolder: |
mov al, 1 |
jmp fs_FloppyRewrite.common |
fs_FloppyRewrite: |
xor eax, eax |
.common: |
cmp byte [esi], 0 |
jz @b |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz fsfrfe |
pushad |
xor ebp, ebp |
push esi |
@@: |
lodsb |
test al, al |
jz @f |
cmp al, '/' |
jnz @b |
lea ebp, [esi-1] |
jmp @b |
@@: |
pop esi |
test ebp, ebp |
jnz .noroot |
call read_flp_root |
cmp [FDC_Status], 0 |
jnz fsfrfe2 |
push flp_rootmem_extend_dir |
push flp_rootmem_end_write |
push flp_rootmem_next_write |
push flp_rootmem_begin_write |
xor ebp, ebp |
push ebp |
push flp_rootmem_first |
push flp_rootmem_next |
jmp .common1 |
.noroot: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [ebp+1], 0 |
jz .ret1 |
; check existence |
mov byte [ebp], 0 |
call fd_find_lfn |
mov byte [ebp], '/' |
lea esi, [ebp+1] |
jnc @f |
mov eax, ERROR_FILE_NOT_FOUND |
.ret1: |
mov [esp+28], eax |
popad |
xor ebx, ebx |
ret |
@@: |
test byte [edi+11], 0x10 ; must be directory |
mov eax, ERROR_ACCESS_DENIED |
jz .ret1 |
movzx ebp, word [edi+26] ; ebp=cluster |
mov eax, ERROR_FAT_TABLE |
cmp ebp, 2 |
jb .ret1 |
cmp ebp, 2849 |
jae .ret1 |
push flp_notroot_extend_dir |
push flp_notroot_end_write |
push flp_notroot_next_write |
push flp_notroot_begin_write |
push ebp |
push flp_notroot_first |
push flp_notroot_next |
.common1: |
call fat_find_lfn |
jc .notfound |
; found |
test byte [edi+11], 10h |
jz .exists_file |
; found directory; if we are creating directory, return OK, |
; if we are creating file, say "access denied" |
add esp, 28 |
popad |
test al, al |
mov eax, ERROR_ACCESS_DENIED |
jz @f |
mov al, 0 |
@@: |
xor ebx, ebx |
ret |
.exists_file: |
; found file; if we are creating directory, return "access denied", |
; if we are creating file, delete existing file and continue |
cmp byte [esp+28+28], 0 |
jz @f |
add esp, 28 |
popad |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
@@: |
; delete FAT chain |
push edi |
xor eax, eax |
mov dword [edi+28], eax ; zero size |
xchg ax, word [edi+26] ; start cluster |
test eax, eax |
jz .done1 |
@@: |
cmp eax, 0xFF8 |
jae .done1 |
lea edi, [FLOPPY_FAT + eax*2] ; position in FAT |
xor eax, eax |
xchg ax, [edi] |
jmp @b |
.done1: |
pop edi |
call get_time_for_file |
mov [edi+22], ax |
call get_date_for_file |
mov [edi+24], ax |
mov [edi+18], ax |
or byte [edi+11], 20h ; set 'archive' attribute |
jmp .doit |
.notfound: |
; file is not found; generate short name |
call fat_name_is_legal |
jc @f |
add esp, 28 |
popad |
mov eax, ERROR_FILE_NOT_FOUND |
xor ebx, ebx |
ret |
@@: |
sub esp, 12 |
mov edi, esp |
call fat_gen_short_name |
.test_short_name_loop: |
push esi edi ecx |
mov esi, edi |
lea eax, [esp+12+12+8] |
mov [eax], ebp |
call dword [eax-4] |
jc .found |
.test_short_name_entry: |
cmp byte [edi+11], 0xF |
jz .test_short_name_cont |
mov ecx, 11 |
push esi edi |
repz cmpsb |
pop edi esi |
jz .short_name_found |
.test_short_name_cont: |
lea eax, [esp+12+12+8] |
call dword [eax-8] |
jnc .test_short_name_entry |
jmp .found |
.short_name_found: |
pop ecx edi esi |
call fat_next_short_name |
jnc .test_short_name_loop |
.disk_full: |
add esp, 12+28 |
popa |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.found: |
pop ecx edi esi |
; now find space in directory |
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~' |
mov al, '~' |
push ecx edi |
mov ecx, 8 |
repnz scasb |
push 1 |
pop eax ; 1 entry |
jnz .notilde |
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total |
xor eax, eax |
@@: |
cmp byte [esi], 0 |
jz @f |
inc esi |
inc eax |
jmp @b |
@@: |
sub esi, eax |
add eax, 12+13 |
mov ecx, 13 |
push edx |
cdq |
div ecx |
pop edx |
.notilde: |
push -1 |
push -1 |
; find <eax> successive entries in directory |
xor ecx, ecx |
push eax |
lea eax, [esp+12+8+12+8] |
mov [eax], ebp |
call dword [eax-4] |
pop eax |
jnc .scan_dir |
.fsfrfe3: |
add esp, 8+8+12+28 |
popad |
mov eax, 11 |
xor ebx, ebx |
ret |
.scan_dir: |
cmp byte [edi], 0 |
jz .free |
cmp byte [edi], 0xE5 |
jz .free |
xor ecx, ecx |
.scan_cont: |
push eax |
lea eax, [esp+12+8+12+8] |
call dword [eax-8] |
pop eax |
jnc .scan_dir |
cmp [FDC_Status], 0 |
jnz .fsfrfe3 |
push eax |
lea eax, [esp+12+8+12+8] |
call dword [eax+16] ; extend directory |
pop eax |
jnc .scan_dir |
add esp, 8+8+12+28 |
popad |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.free: |
test ecx, ecx |
jnz @f |
mov [esp], edi |
mov ecx, [esp+8+8+12+8] |
mov [esp+4], ecx |
xor ecx, ecx |
@@: |
inc ecx |
cmp ecx, eax |
jb .scan_cont |
; found! |
; calculate name checksum |
push esi ecx |
mov esi, [esp+8+8] |
mov ecx, 11 |
xor eax, eax |
@@: |
ror al, 1 |
add al, [esi] |
inc esi |
loop @b |
pop ecx esi |
pop edi |
pop dword [esp+8+12+8] |
; edi points to first entry in free chunk |
dec ecx |
jz .nolfn |
push esi |
push eax |
lea eax, [esp+8+8+12+8] |
call dword [eax+4] ; begin write |
mov al, 40h |
.writelfn: |
or al, cl |
mov esi, [esp+4] |
push ecx |
dec ecx |
imul ecx, 13 |
add esi, ecx |
stosb |
mov cl, 5 |
call fs_RamdiskRewrite.read_symbols |
mov ax, 0xF |
stosw |
mov al, [esp+4] |
stosb |
mov cl, 6 |
call fs_RamdiskRewrite.read_symbols |
xor eax, eax |
stosw |
mov cl, 2 |
call fs_RamdiskRewrite.read_symbols |
pop ecx |
lea eax, [esp+8+8+12+8] |
call dword [eax+8] ; next write |
xor eax, eax |
loop .writelfn |
pop eax |
pop esi |
; lea eax, [esp+8+12+8] |
; call dword [eax+12] ; end write |
.nolfn: |
xchg esi, [esp] |
mov ecx, 11 |
rep movsb |
mov word [edi], 20h ; attributes |
sub edi, 11 |
pop esi ecx |
add esp, 12 |
mov byte [edi+13], 0 ; tenths of a second at file creation time |
call get_time_for_file |
mov [edi+14], ax ; creation time |
mov [edi+22], ax ; last write time |
call get_date_for_file |
mov [edi+16], ax ; creation date |
mov [edi+24], ax ; last write date |
mov [edi+18], ax ; last access date |
and word [edi+20], 0 ; high word of cluster |
and word [edi+26], 0 ; low word of cluster - to be filled |
and dword [edi+28], 0 ; file size - to be filled |
cmp byte [esp+28+28], 0 |
jz .doit |
; create directory |
mov byte [edi+11], 10h ; attributes: folder |
mov ecx, 32*2 |
mov edx, edi |
.doit: |
lea eax, [esp+8] |
call dword [eax+12] ; flush directory |
push ecx |
push edi |
push 0 |
mov esi, edx |
test ecx, ecx |
jz .done |
mov ecx, 2849 |
mov edi, FLOPPY_FAT |
push 0 ; first cluster |
.write_loop: |
; allocate new cluster |
xor eax, eax |
repnz scasw |
mov al, ERROR_DISK_FULL |
jnz .ret |
dec edi |
dec edi |
lea eax, [edi-(FLOPPY_FAT)] |
shr eax, 1 ; eax = cluster |
mov word [edi], 0xFFF ; mark as last cluster |
xchg edi, [esp+4] |
cmp dword [esp], 0 |
jz .first |
stosw |
jmp @f |
.first: |
mov [esp], eax |
@@: |
mov edi, [esp+4] |
inc ecx |
; write data |
push ecx edi |
mov ecx, 512 |
cmp dword [esp+20], ecx |
jae @f |
mov ecx, [esp+20] |
@@: |
mov edi, 0xD000 |
cmp byte [esp+24+28+28], 0 |
jnz .writedir |
push ecx |
rep movsb |
pop ecx |
.writedircont: |
push ecx |
sub ecx, 512 |
neg ecx |
push eax |
xor eax, eax |
rep stosb |
pop eax |
add eax, 31 |
pusha |
call save_chs_sector |
popa |
pop ecx |
cmp [FDC_Status], 0 |
jnz .diskerr |
sub [esp+20], ecx |
pop edi ecx |
jnz .write_loop |
.done: |
xor eax, eax |
.ret: |
pop ebx edi edi ecx |
mov [esp+28+28], eax |
lea eax, [esp+8] |
call dword [eax+4] |
mov [edi+26], bx |
mov ebx, esi |
sub ebx, edx |
mov [edi+28], ebx |
call dword [eax+12] |
mov [esp+28+16], ebx |
test ebp, ebp |
jnz @f |
call save_flp_root |
@@: |
add esp, 28 |
cmp [FDC_Status], 0 |
jnz .err3 |
call save_flp_fat |
cmp [FDC_Status], 0 |
jnz .err3 |
popa |
ret |
.err3: |
popa |
mov al, 11 |
xor ebx, ebx |
ret |
.diskerr: |
sub esi, ecx |
mov eax, 11 |
pop edi ecx |
jmp .ret |
.writedir: |
push ecx |
mov ecx, 32/4 |
push ecx esi |
rep movsd |
pop esi ecx |
mov dword [edi-32], '. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
mov word [edi-32+26], ax |
push esi |
rep movsd |
pop esi |
mov dword [edi-32], '.. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
mov ecx, [esp+28+8] |
mov word [edi-32+26], cx |
pop ecx |
jmp .writedircont |
;---------------------------------------------------------------- |
; |
; fs_FloppyWrite - LFN variant for writing to floppy |
; |
; 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 |
; |
;-------------------------------------------------------------- |
@@: |
push ERROR_ACCESS_DENIED |
fs_FloppyWrite.ret0: |
pop eax |
xor ebx, ebx |
ret |
fs_FloppyWrite.ret11: |
push 11 |
jmp fs_FloppyWrite.ret0 |
fs_FloppyWrite: |
cmp byte [esi], 0 |
jz @b |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz .ret11 |
pushad |
call fd_find_lfn |
jnc .found |
popad |
push ERROR_FILE_NOT_FOUND |
jmp .ret0 |
.found: |
; FAT does not support files larger than 4GB |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
.eof: |
popad |
push ERROR_END_OF_FILE |
jmp .ret0 |
@@: |
mov ebx, [ebx] |
.l1: |
; now edi points to direntry, ebx=start byte to write, |
; ecx=number of bytes to write, edx=data pointer |
; extend file if needed |
add ecx, ebx |
jc .eof ; FAT does not support files larger than 4GB |
push eax ; save directory cluster |
push 0 ; return value=0 |
call get_time_for_file |
mov [edi+22], ax ; last write time |
call get_date_for_file |
mov [edi+24], ax ; last write date |
mov [edi+18], ax ; last access date |
push dword [edi+28] ; save current file size |
cmp ecx, [edi+28] |
jbe .length_ok |
cmp ecx, ebx |
jz .length_ok |
call floppy_extend_file |
jnc .length_ok |
mov [esp+4], eax |
; floppy_extend_file can return two error codes: FAT table error or disk full. |
; First case is fatal error, in second case we may write some data |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
pop eax |
pop eax |
mov [esp+4+28], eax |
pop eax |
popad |
xor ebx, ebx |
ret |
.disk_full: |
; correct number of bytes to write |
mov ecx, [edi+28] |
cmp ecx, ebx |
ja .length_ok |
.ret: |
pop eax |
pop eax |
mov [esp+4+28], eax ; eax=return value |
pop eax |
sub edx, [esp+20] |
mov [esp+16], edx ; ebx=number of written bytes |
popad |
ret |
.length_ok: |
; save FAT & directory |
; note that directory must be saved first because save_flp_fat uses buffer at 0xD000 |
mov esi, [edi+28] |
movzx edi, word [edi+26] ; starting cluster |
mov eax, [esp+8] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err |
call save_flp_fat |
cmp [FDC_Status], 0 |
jz @f |
.device_err: |
mov byte [esp+4], 11 |
jmp .ret |
@@: |
; now ebx=start pos, ecx=end pos, both lie inside file |
sub ecx, ebx |
jz .ret |
call SetUserInterrupts |
.write_loop: |
; skip unmodified sectors |
cmp dword [esp], 0x200 |
jb .modify |
sub ebx, 0x200 |
jae .skip |
add ebx, 0x200 |
.modify: |
lea eax, [edi+31] ; current sector |
; get length of data in current sector |
push ecx |
sub ebx, 0x200 |
jb .hasdata |
neg ebx |
xor ecx, ecx |
jmp @f |
.hasdata: |
neg ebx |
cmp ecx, ebx |
jbe @f |
mov ecx, ebx |
@@: |
; load sector if needed |
cmp dword [esp+4], 0 ; we don't need to read uninitialized data |
jz .noread |
cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten |
jz .noread |
cmp ecx, esi ; (same for the last sector) |
jz .noread |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jz @f |
.device_err2: |
pop ecx |
jmp .device_err |
@@: |
.noread: |
; zero uninitialized data if file was extended (because floppy_extend_file does not this) |
push eax ecx edi |
xor eax, eax |
mov ecx, 0x200 |
sub ecx, [esp+4+12] |
jbe @f |
mov edi, 0xD000 |
add edi, [esp+4+12] |
rep stosb |
@@: |
; zero uninitialized data in the last sector |
mov ecx, 0x200 |
sub ecx, esi |
jbe @f |
mov edi, 0xD000 |
add edi, esi |
rep stosb |
@@: |
pop edi ecx eax |
; copy new data |
push eax |
mov eax, edx |
neg ebx |
jecxz @f |
add ebx, 0xD000+0x200 |
call memmove |
xor ebx, ebx |
@@: |
pop eax |
; save sector |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err2 |
add edx, ecx |
sub [esp], ecx |
pop ecx |
jz .done |
.skip: |
.next_cluster: |
movzx edi, word [edi*2+0x282000] |
sub esi, 0x200 |
jae @f |
xor esi, esi |
@@: |
sub dword [esp], 0x200 |
jae .write_loop |
and dword [esp], 0 |
jmp .write_loop |
.done: |
mov [fdc_irq_func], fdc_null |
jmp .ret |
floppy_extend_file.zero_size: |
xor eax, eax |
jmp floppy_extend_file.start_extend |
; extends file on floppy to given size (new data area is undefined) |
; in: edi->direntry, ecx=new size |
; out: CF=0 => OK, eax=0 |
; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL) |
floppy_extend_file: |
push ecx |
; find the last cluster of file |
movzx eax, word [edi+26] ; first cluster |
mov ecx, [edi+28] |
jecxz .zero_size |
@@: |
sub ecx, 0x200 |
jbe @f |
mov eax, [eax*2+0x282000] |
and eax, 0xFFF |
jz .fat_err |
cmp eax, 0xFF8 |
jb @b |
.fat_err: |
pop ecx |
push ERROR_FAT_TABLE |
pop eax |
stc |
ret |
@@: |
push eax |
mov eax, [eax*2+0x282000] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
pop eax |
jb .fat_err |
; set length to full number of sectors |
sub [edi+28], ecx |
.start_extend: |
pop ecx |
; now do extend |
push edx esi |
mov esi, 0x282000+2*2 ; start scan from cluster 2 |
mov edx, 2847 ; number of clusters to scan |
.extend_loop: |
cmp [edi+28], ecx |
jae .extend_done |
; add new sector |
push ecx |
push edi |
.scan: |
mov ecx, edx |
mov edi, esi |
jecxz .disk_full |
push eax |
xor eax, eax |
repnz scasw |
pop eax |
jnz .disk_full |
mov word [edi-2], 0xFFF |
mov esi, edi |
mov edx, ecx |
sub edi, 0x282000 |
shr edi, 1 |
dec edi ; now edi=new cluster |
test eax, eax |
jz .first_cluster |
mov [0x282000+eax*2], di |
jmp @f |
.first_cluster: |
pop eax ; eax->direntry |
push eax |
mov [eax+26], di |
@@: |
mov eax, edi ; eax=new cluster |
pop edi ; edi->direntry |
pop ecx ; ecx=required size |
add dword [edi+28], 0x200 |
jmp .extend_loop |
.extend_done: |
mov [edi+28], ecx |
pop esi edx |
xor eax, eax ; CF=0 |
ret |
.disk_full: |
pop edi ecx |
pop esi edx |
stc |
push ERROR_DISK_FULL |
pop eax |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppySetFileEnd - set end of file on floppy |
; |
; 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 |
; |
;-------------------------------------------------------------- |
fs_FloppySetFileEnd: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz ret11 |
cmp byte [esi], 0 |
jnz @f |
.access_denied: |
push ERROR_ACCESS_DENIED |
jmp .ret |
@@: |
push edi |
call fd_find_lfn |
jnc @f |
pop edi |
push ERROR_FILE_NOT_FOUND |
.ret: |
pop eax |
jmp .doret |
@@: |
; must not be directory |
test byte [edi+11], 10h |
jz @f |
pop edi |
jmp .access_denied |
@@: |
; file size must not exceed 4 Gb |
cmp dword [ebx+4], 0 |
jz @f |
pop edi |
push ERROR_END_OF_FILE |
jmp .ret |
@@: |
push eax |
; set file modification date/time to current |
call fat_update_datetime |
mov eax, [ebx] |
cmp eax, [edi+28] |
jb .truncate |
ja .expand |
pop eax |
pushad |
call save_chs_sector |
popad |
pop edi |
xor eax, eax |
cmp [FDC_Status], 0 |
jz @f |
mov al, 11 |
@@: |
.doret: |
mov [fdc_irq_func], fdc_null |
ret |
.expand: |
push ecx |
push dword [edi+28] ; save old size |
mov ecx, eax |
call floppy_extend_file |
push eax ; return code |
jnc .expand_ok |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
pop eax ecx ecx edi edi |
jmp .doret |
.device_err: |
pop eax |
.device_err2: |
pop ecx ecx eax edi |
push 11 |
jmp .ret |
.disk_full: |
.expand_ok: |
; save directory & FAT |
mov eax, [edi+28] |
xchg eax, [esp+12] |
movzx edi, word [edi+26] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err |
call save_flp_fat |
cmp [FDC_Status], 0 |
jnz .device_err |
call SetUserInterrupts |
; now zero new data |
; edi = current cluster, [esp+12]=new size, [esp+4]=old size, [esp]=return code |
.zero_loop: |
sub dword [esp+4], 0x200 |
jae .next_cluster |
cmp dword [esp+4], -0x200 |
jz .noread |
lea eax, [edi+31] |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .err_next |
.noread: |
mov ecx, [esp+4] |
neg ecx |
push edi |
mov edi, 0xD000+0x200 |
add edi, [esp+8] |
xor eax, eax |
mov [esp+8], eax |
rep stosb |
pop edi |
lea eax, [edi+31] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jz .next_cluster |
.err_next: |
mov byte [esp], 11 |
.next_cluster: |
sub dword [esp+12], 0x200 |
jbe .expand_done |
movzx edi, word [0x282000+edi*2] |
jmp .zero_loop |
.expand_done: |
pop eax ecx ecx edi edi |
jmp .doret |
.truncate: |
mov [edi+28], eax |
push ecx |
movzx ecx, word [edi+26] |
test eax, eax |
jz .zero_size |
; find new last sector |
@@: |
sub eax, 0x200 |
jbe @f |
movzx ecx, word [0x282000+ecx*2] |
jmp @b |
@@: |
; we will zero data at the end of last sector - remember it |
push ecx |
; terminate FAT chain |
lea ecx, [0x282000+ecx+ecx] |
push dword [ecx] |
mov word [ecx], 0xFFF |
pop ecx |
and ecx, 0xFFF |
jmp .delete |
.zero_size: |
and word [edi+26], 0 |
push 0 |
.delete: |
; delete FAT chain starting with ecx |
; mark all clusters as free |
cmp ecx, 0xFF8 |
jae .deleted |
lea ecx, [0x282000+ecx+ecx] |
push dword [ecx] |
and word [ecx], 0 |
pop ecx |
and ecx, 0xFFF |
jmp .delete |
.deleted: |
mov edi, [edi+28] |
; save directory & FAT |
mov eax, [esp+8] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err2 |
call save_flp_fat |
cmp [FDC_Status], 0 |
jnz .device_err2 |
; zero last sector, ignore errors |
pop eax |
add eax, 31 |
and edi, 0x1FF |
jz .truncate_done |
call SetUserInterrupts |
pusha |
call read_chs_sector |
popa |
add edi, 0xD000 |
mov ecx, 0xD000+0x200 |
sub ecx, edi |
push eax |
xor eax, eax |
rep stosb |
pop eax |
pusha |
call save_chs_sector |
popa |
.truncate_done: |
pop ecx eax edi |
xor eax, eax |
jmp .doret |
fs_FloppyGetFileInfo: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz ret11 |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 ; unsupported |
ret |
@@: |
push edi |
call fd_find_lfn |
jmp fs_GetFileInfo_finish |
ret11: |
mov eax, 11 |
ret |
fs_FloppySetFileInfo: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz ret11 |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 ; unsupported |
ret |
@@: |
push edi |
call fd_find_lfn |
jnc @f |
pop edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
push eax |
call bdfe_to_fat_entry |
pop eax |
pusha |
call save_chs_sector |
popa |
pop edi |
xor eax, eax |
cmp [FDC_Status], 0 |
jz @f |
mov al, 11 |
@@: |
ret |
if 0 |
;---------------------------------------------------------------- |
; |
; fs_FloppyExecute - LFN variant for executing from floppy |
; |
; esi points to floppy filename (e.g. 'dir1/name') |
; ebp points to full filename (e.g. '/fd/1/dir1/name') |
; dword [ebx] = flags |
; dword [ebx+4] = cmdline |
; |
; ret ebx,edx destroyed |
; eax > 0 - PID, < 0 - error |
; |
;-------------------------------------------------------------- |
fs_FloppyExecute: |
mov edx, [ebx] |
mov ebx, [ebx+4] |
test ebx, ebx |
jz @f |
add ebx, std_application_base_address |
@@: |
;---------------------------------------------------------------- |
; |
; fs_FloppyExecute.flags - second entry |
; |
; esi points to floppy filename (kernel address) |
; ebp points to full filename |
; edx flags |
; ebx cmdline (kernel address) |
; |
; ret eax > 0 - PID, < 0 - error |
; |
;-------------------------------------------------------------- |
.flags: |
call read_flp_fat |
cmp byte [esi], 0 |
jnz @f |
; cannot execute root! |
mov eax, -ERROR_ACCESS_DENIED |
ret |
@@: |
push edi |
call fd_find_lfn |
jnc .found |
pop edi |
mov eax, -ERROR_FILE_NOT_FOUND |
ret |
.found: |
movzx eax, word [edi+26] ; cluster |
push eax |
push dword [edi+28] ; size |
push .DoRead |
call fs_execute |
add esp, 12 |
pop edi |
ret |
.DoRead: |
; read next block |
; in: eax->parameters, edi->buffer |
; out: eax = error code |
pushad |
cmp dword [eax], 0 ; file size |
jz .eof |
mov eax, [eax+4] ; cluster |
add eax, 31 |
call read_chs_sector |
cmp [FDC_Status], 0 |
jnz .err |
pop edi |
mov esi, 0xD000 |
push edi |
mov ecx, 512/4 |
rep movsd |
mov eax, [esp+28] |
mov ecx, [eax] |
sub ecx, 512 |
jae @f |
add edi, ecx |
neg ecx |
push eax |
xor eax, eax |
rep stosb |
pop eax |
@@: |
mov [eax], ecx |
mov edx, [eax+4] |
mov dx, [edx*2+0x282000] |
mov [eax+4], dx ; high word is already zero |
popad |
xor eax, eax |
ret |
.eof: |
popad |
mov eax, 6 |
ret |
.err: |
popad |
mov eax, 11 |
ret |
end if |
;---------------------------------------------------------------- |
; |
; fs_FloppyDelete - delete file or empty folder from floppy |
; |
; esi points to filename |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_FloppyDelete: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jz @f |
push 11 |
jmp .pop_ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
; cannot delete root! |
.access_denied: |
push ERROR_ACCESS_DENIED |
.pop_ret: |
pop eax |
ret |
@@: |
and [fd_prev_sector], 0 |
and [fd_prev_prev_sector], 0 |
push edi |
call fd_find_lfn |
jnc .found |
pop edi |
push ERROR_FILE_NOT_FOUND |
jmp .pop_ret |
.found: |
cmp dword [edi], '. ' |
jz .access_denied2 |
cmp dword [edi], '.. ' |
jz .access_denied2 |
test byte [edi+11], 10h |
jz .dodel |
; we can delete only empty folders! |
push eax |
movzx eax, word [edi+26] |
push ebx |
pusha |
add eax, 31 |
call read_chs_sector |
popa |
mov ebx, FDD_DATA + 2*0x20 |
.checkempty: |
cmp byte [ebx], 0 |
jz .empty |
cmp byte [ebx], 0xE5 |
jnz .notempty |
add ebx, 0x20 |
cmp ebx, FDD_DATA + 0x200 |
jb .checkempty |
movzx eax, word [FLOPPY_FAT + eax*2] |
pusha |
add eax, 31 |
call read_chs_sector |
popa |
mov ebx, FDD_DATA |
jmp .checkempty |
.notempty: |
pop ebx |
pop eax |
.access_denied2: |
pop edi |
jmp .access_denied |
.empty: |
pop ebx |
pop eax |
pusha |
call read_chs_sector |
popa |
.dodel: |
push eax |
movzx eax, word [edi+26] |
xchg eax, [esp] |
; delete folder entry |
mov byte [edi], 0xE5 |
; delete LFN (if present) |
.lfndel: |
cmp edi, FDD_DATA |
ja @f |
cmp [fd_prev_sector], 0 |
jz .lfndone |
push [fd_prev_sector] |
push [fd_prev_prev_sector] |
pop [fd_prev_sector] |
and [fd_prev_prev_sector], 0 |
pusha |
call save_chs_sector |
popa |
pop eax |
pusha |
call read_chs_sector |
popa |
mov edi, FDD_DATA+0x200 |
@@: |
sub edi, 0x20 |
cmp byte [edi], 0xE5 |
jz .lfndone |
cmp byte [edi+11], 0xF |
jnz .lfndone |
mov byte [edi], 0xE5 |
jmp .lfndel |
.lfndone: |
pusha |
call save_chs_sector |
popa |
; delete FAT chain |
pop eax |
test eax, eax |
jz .done |
@@: |
lea eax, [FLOPPY_FAT + eax*2] |
push dword [eax] |
and word [eax], 0 |
pop eax |
and eax, 0xFFF |
jnz @b |
.done: |
call save_flp_fat |
pop edi |
xor eax, eax |
ret |
; \end{diamond} |
/kernel/tags/kolibri0.6.5.0/fs/fat32.inc |
---|
0,0 → 1,3523 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; FAT32.INC ;; |
;; ;; |
;; FAT16/32 functions for KolibriOS ;; |
;; ;; |
;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;; |
;; ;; |
;; See file COPYING for details ;; |
;; 04.02.2007 LFN create folder - diamond ;; |
;; 08.10.2006 LFN delete file/folder - diamond ;; |
;; 20.08.2006 LFN set file size (truncate/extend) - diamond ;; |
;; 17.08.2006 LFN write/append to file - diamond ;; |
;; 23.06.2006 LFN start application - diamond ;; |
;; 15.06.2006 LFN get/set file/folder info - diamond ;; |
;; 27.05.2006 LFN create/rewrite file - diamond ;; |
;; 04.05.2006 LFN read folder - diamond ;; |
;; 29.04.2006 Elimination of hangup after the ;; |
;; expiration hd_wait_timeout - Mario79 ;; |
;; 23.04.2006 LFN read file - diamond ;; |
;; 28.01.2006 find all Fat16/32 partition in all input point ;; |
;; to MBR, see file part_set.inc - Mario79 ;; |
;; 15.01.2005 get file size/attr/date, file_append - ATV ;; |
;; 04.12.2004 skip volume label, file delete bug fixed - ATV ;; |
;; 29.11.2004 get_free_FAT changed, append dir bug fixed - ATV ;; |
;; 23.11.2004 don't allow overwrite dir with file - ATV ;; |
;; 18.11.2004 get_disk_info and more error codes - ATV ;; |
;; 17.11.2004 set_FAT/get_FAT and disk cache rewritten - ATV ;; |
;; 10.11.2004 removedir clear whole directory structure - ATV ;; |
;; 08.11.2004 rename - ATV ;; |
;; 30.10.2004 file_read return also dirsize in bytes - ATV ;; |
;; 20.10.2004 Makedir/Removedir - ATV ;; |
;; 14.10.2004 Partition chain/Fat16 - ATV (thanks drh3xx) ;; |
;; 06.9.2004 Fix free space by Mario79 added - MH ;; |
;; 24.5.2004 Write back buffer for File_write -VT ;; |
;; 20.5.2004 File_read function to work with syscall 58 - VT ;; |
;; 30.3.2004 Error parameters at function return - VT ;; |
;; 01.5.2002 Bugfix in device write - VT ;; |
;; 20.5.2002 Hd status check - VT ;; |
;; 29.6.2002 Improved fat32 verification - VT ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
cache_max equ 1919 ; max. is 1919*512+0x610000=0x6ffe00 |
ERROR_SUCCESS = 0 |
ERROR_DISK_BASE = 1 |
ERROR_UNSUPPORTED_FS = 2 |
ERROR_UNKNOWN_FS = 3 |
ERROR_PARTITION = 4 |
ERROR_FILE_NOT_FOUND = 5 |
ERROR_END_OF_FILE = 6 |
ERROR_MEMORY_POINTER = 7 |
ERROR_DISK_FULL = 8 |
ERROR_FAT_TABLE = 9 |
ERROR_ACCESS_DENIED = 10 |
PUSHAD_EAX equ [esp+28] |
PUSHAD_ECX equ [esp+24] |
PUSHAD_EDX equ [esp+20] |
PUSHAD_EBX equ [esp+16] |
PUSHAD_EBP equ [esp+8] |
PUSHAD_ESI equ [esp+4] |
PUSHAD_EDI equ [esp+0] |
uglobal |
align 4 |
cluster dd 0 ; used by file_write,makedir,append |
partition_count dd 0 ; partitions found by set_FAT32_variables |
longname_sec1 dd 0 ; used by analyze_directory to save 2 previous |
longname_sec2 dd 0 ; directory sectors for delete long filename |
hd_error dd 0 ; set by wait_for_sector_buffer |
hd_setup dd 0 |
hd_wait_timeout dd 0 |
cluster_tmp dd 0 ; used by analyze_directory |
; and analyze_directory_to_write |
file_size dd 0 ; used by file_read |
sector_tmp dd 0 ; used by rename,append,file_write |
entry_pos dd 0 ; used by rename,append,file_write |
old_filesize dd 0 ; used by append |
new_filepos dd 0 ; used by append |
bytes2write dd 0 ; used by append |
cache_search_start dd 0 ; used by find_empty_slot |
endg |
iglobal |
fat_in_cache dd -1 |
endg |
uglobal |
align 4 |
fat_cache: times 512 db 0 |
Sector512: ; label for dev_hdcd.inc |
buffer: times 512 db 0 |
fsinfo_buffer: times 512 db 0 |
endg |
uglobal |
dir_entry: times 32 db 0 |
startpath: times 255 db 0 |
fat16_root db 0 ; flag for fat16 rootdir |
fat_change db 0 ; 1=fat has changed |
endg |
reserve_hd1: |
cli |
cmp [hd1_status],0 |
je reserve_ok1 |
sti |
call change_task |
jmp reserve_hd1 |
reserve_ok1: |
push eax |
mov eax,[0x3000] |
shl eax,5 |
mov eax,[eax+0x3000+TASKDATA.pid] |
mov [hd1_status],eax |
pop eax |
sti |
ret |
;******************************************** |
uglobal |
hd_in_cache db ? |
endg |
reserve_hd_channel: |
cmp [hdbase], 0x1F0 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
cli |
cmp [IDE_Channel_1],0 |
je .reserve_ok_1 |
sti |
call change_task |
jmp .IDE_Channel_1 |
.IDE_Channel_2: |
cli |
cmp [IDE_Channel_2],0 |
je .reserve_ok_2 |
sti |
call change_task |
jmp .IDE_Channel_2 |
.reserve_ok_1: |
mov [IDE_Channel_1], 1 |
push eax |
mov al, 1 |
jmp @f |
.reserve_ok_2: |
mov [IDE_Channel_2], 1 |
push eax |
mov al, 3 |
@@: |
cmp [hdid], 1 |
sbb al, -1 |
cmp al, [hd_in_cache] |
jz @f |
mov [hd_in_cache], al |
call clear_hd_cache |
@@: |
pop eax |
ret |
free_hd_channel: |
cmp [hdbase], 0x1F0 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
mov [IDE_Channel_1],0 |
ret |
.IDE_Channel_2: |
mov [IDE_Channel_2],0 |
ret |
;******************************************** |
problem_partition db 0 ; used for partitions search |
include 'part_set.inc' |
set_FAT: |
;-------------------------------- |
; input : EAX = cluster |
; EDX = value to save |
; output : EDX = old value |
;-------------------------------- |
push eax ebx esi |
cmp eax,2 |
jb sfc_error |
cmp eax,[LAST_CLUSTER] |
ja sfc_error |
cmp [fs_type],16 |
je sfc_1 |
add eax,eax |
sfc_1: |
add eax,eax |
mov esi,511 |
and esi,eax ; esi = position in fat sector |
shr eax,9 ; eax = fat sector |
add eax,[FAT_START] |
mov ebx,fat_cache |
cmp eax,[fat_in_cache] ; is fat sector already in memory? |
je sfc_in_cache ; yes |
cmp [fat_change],0 ; is fat changed? |
je sfc_no_change ; no |
call write_fat_sector ; yes. write it into disk |
cmp [hd_error],0 |
jne sfc_error |
sfc_no_change: |
mov [fat_in_cache],eax ; save fat sector |
call hd_read |
cmp [hd_error],0 |
jne sfc_error |
sfc_in_cache: |
cmp [fs_type],16 |
jne sfc_test32 |
sfc_set16: |
xchg [ebx+esi],dx ; save new value and get old value |
jmp sfc_write |
sfc_test32: |
mov eax,[fatMASK] |
sfc_set32: |
and edx,eax |
xor eax,-1 ; mask for high bits |
and eax,[ebx+esi] ; get high 4 bits |
or eax,edx |
mov edx,[ebx+esi] ; get old value |
mov [ebx+esi],eax ; save new value |
sfc_write: |
mov [fat_change],1 ; fat has changed |
sfc_nonzero: |
and edx,[fatMASK] |
sfc_error: |
pop esi ebx eax |
ret |
get_FAT: |
;-------------------------------- |
; input : EAX = cluster |
; output : EAX = next cluster |
;-------------------------------- |
push ebx esi |
cmp [fs_type],16 |
je gfc_1 |
add eax,eax |
gfc_1: |
add eax,eax |
mov esi,511 |
and esi,eax ; esi = position in fat sector |
shr eax,9 ; eax = fat sector |
add eax,[FAT_START] |
mov ebx,fat_cache |
cmp eax,[fat_in_cache] ; is fat sector already in memory? |
je gfc_in_cache |
cmp [fat_change],0 ; is fat changed? |
je gfc_no_change ; no |
call write_fat_sector ; yes. write it into disk |
cmp [hd_error],0 |
jne hd_error_01 |
gfc_no_change: |
mov [fat_in_cache],eax |
call hd_read |
cmp [hd_error],0 |
jne hd_error_01 |
gfc_in_cache: |
mov eax,[ebx+esi] |
and eax,[fatMASK] |
hd_error_01: |
pop esi ebx |
ret |
get_free_FAT: |
;----------------------------------------------------------- |
; input : EAX = # cluster for start the searching |
; output : if CARRY=0 EAX = # first cluster found free |
; if CARRY=1 disk full |
; Note : for more speed need to use fat_cache directly |
;----------------------------------------------------------- |
push ecx |
mov ecx,[LAST_CLUSTER] ; counter for full disk |
sub ecx,2 |
gff_test: |
cmp eax,[LAST_CLUSTER] ; if above last cluster start at cluster 2 |
jbe gff_in_range |
mov eax,2 |
gff_in_range: |
push eax |
call get_FAT ; get cluster state |
cmp [hd_error],0 |
jne gff_not_found_1 |
test eax,eax ; is it free? |
pop eax |
je gff_found ; yes |
inc eax ; next cluster |
dec ecx ; is all checked? |
jns gff_test ; no |
gff_not_found_1: |
add esp,4 |
gff_not_found: |
pop ecx ; yes. disk is full |
stc |
ret |
gff_found: |
pop ecx |
clc |
ret |
write_fat_sector: |
;----------------------------------------------------------- |
; write changed fat to disk |
;----------------------------------------------------------- |
push eax ebx ecx |
mov [fat_change],0 |
mov eax,[fat_in_cache] |
cmp eax,-1 |
jz write_fat_not_used |
mov ebx,fat_cache |
mov ecx,[NUMBER_OF_FATS] |
write_next_fat: |
call hd_write |
cmp [hd_error],0 |
jne write_fat_not_used |
add eax,[SECTORS_PER_FAT] |
dec ecx |
jnz write_next_fat |
write_fat_not_used: |
pop ecx ebx eax |
ret |
analyze_directory: |
;----------------------------------------------------------- |
; input : EAX = first cluster of the directory |
; EBX = pointer to filename |
; output : IF CARRY=0 EAX = sector where th file is found |
; EBX = pointer in buffer |
; [buffer .. buffer+511] |
; ECX,EDX,ESI,EDI not changed |
; IF CARRY=1 filename not found |
; Note : if cluster=0 it's changed to read rootdir |
; save 2 previous directory sectors in longname_sec |
;----------------------------------------------------------- |
push ecx edx esi edi ebx ; ebx = [esp+0] |
mov [longname_sec1],0 |
mov [longname_sec2],0 |
adr_new_cluster: |
mov [cluster_tmp],eax |
mov [fat16_root],0 |
cmp eax,[LAST_CLUSTER] |
ja adr_not_found ; too big cluster number, something is wrong |
cmp eax,2 |
jnb adr_data_cluster |
mov eax,[ROOT_CLUSTER] ; if cluster < 2 then read rootdir |
cmp [fs_type],16 |
jne adr_data_cluster |
mov eax,[ROOT_START] |
mov edx,[ROOT_SECTORS] |
mov [fat16_root],1 ; flag for fat16 rootdir |
jmp adr_new_sector |
adr_data_cluster: |
sub eax,2 |
mov edx,[SECTORS_PER_CLUSTER] |
imul eax,edx |
add eax,[DATA_START] |
adr_new_sector: |
mov ebx,buffer |
call hd_read |
cmp [hd_error],0 |
jne adr_not_found |
mov ecx,512/32 ; count of dir entrys per sector = 16 |
adr_analyze: |
mov edi,[ebx+11] ; file attribute |
and edi,0xf |
cmp edi,0xf |
je adr_long_filename |
test edi,0x8 ; skip over volume label |
jne adr_long_filename ; Note: label can be same name as file/dir |
mov esi,[esp+0] ; filename need to be uppercase |
mov edi,ebx |
push ecx |
mov ecx,11 |
cld |
rep cmpsb ; compare 8+3 filename |
pop ecx |
je adr_found |
adr_long_filename: |
add ebx,32 ; position of next dir entry |
dec ecx |
jnz adr_analyze |
mov ecx,[longname_sec1] ; save 2 previous directory sectors |
mov [longname_sec1],eax ; for delete long filename |
mov [longname_sec2],ecx |
inc eax ; next sector |
dec edx |
jne adr_new_sector |
cmp [fat16_root],1 ; end of fat16 rootdir |
je adr_not_found |
adr_next_cluster: |
mov eax,[cluster_tmp] |
call get_FAT ; get next cluster |
cmp [hd_error],0 |
jne adr_not_found |
cmp eax,2 ; incorrect fat chain? |
jb adr_not_found ; yes |
cmp eax,[fatRESERVED] ; is it end of directory? |
jb adr_new_cluster ; no. analyse it |
adr_not_found: |
pop edi edi esi edx ecx ; first edi will remove ebx |
stc ; file not found |
ret |
adr_found: |
pop edi edi esi edx ecx ; first edi will remove ebx |
clc ; file found |
ret |
analyze_directory_to_write: |
;----------------------------------------------------------- |
; input : EAX = first cluster of the directory |
; output : IF CARRY=0 EAX = sector where the empty pos is found |
; EBX = pointer in buffer |
; [buffer .. buffer+511] |
; ECX,EDX,ESI,EDI not changed |
; IF CARRY=1 disk full or fat corrupted |
; Note : if cluster=0 it's changed to read rootdir |
;----------------------------------------------------------- |
push ecx edx edi |
adw_new_cluster: |
mov [cluster_tmp],eax |
mov [fat16_root],0 |
cmp eax,[LAST_CLUSTER] |
ja adw_not_found ; too big cluster number, something is wrong |
cmp eax,2 |
jnb adw_data_cluster |
mov eax,[ROOT_CLUSTER] ; if cluster < 2 then read rootdir |
cmp [fs_type],16 |
jne adw_data_cluster |
mov eax,[ROOT_START] |
mov edx,[ROOT_SECTORS] |
mov [fat16_root],1 ; flag for fat16 rootdir |
jmp adw_new_sector |
adw_data_cluster: |
sub eax,2 |
mov edx,[SECTORS_PER_CLUSTER] |
imul eax,edx |
add eax,[DATA_START] |
adw_new_sector: |
mov ebx,buffer |
call hd_read |
cmp [hd_error],0 |
jne adw_not_found |
mov ecx,512/32 ; count of dir entrys per sector = 16 |
adw_analyze: |
cmp byte [ebx],0x00 ; is free entry? |
je adw_found ; yes |
cmp byte [ebx],0xe5 ; is deleted entry? |
je adw_found ; yes |
add ebx,32 ; position of next dir entry |
dec ecx |
jnz adw_analyze |
inc eax ; next sector |
dec edx |
jne adw_new_sector |
cmp [fat16_root],1 ; end of fat16 rootdir |
je adw_not_found |
mov eax,[cluster_tmp] |
call get_FAT ; get next cluster |
cmp [hd_error],0 |
jne adw_not_found |
cmp eax,2 ; incorrect fat chain? |
jb adw_not_found ; yes |
cmp eax,[fatRESERVED] ; is it end of directory? |
jb adw_new_cluster ; no. analyse it |
mov eax,2 ; this block of code add a new cluster |
call get_free_FAT ; for the directory because the directory |
jc adw_not_found ; is full |
mov edx,[fatEND] ; new end for directory |
call set_FAT |
cmp [hd_error],0 |
jne adw_not_found |
push eax ; save new cluster |
mov edx,eax |
mov eax,[cluster_tmp] ; change last cluster to point new cluster |
call set_FAT |
cmp [hd_error],0 |
jne adw_not_found_1 |
mov ecx,-1 ; remove 1 cluster from free disk space |
call add_disk_free_space |
cmp [hd_error],0 |
jne adw_not_found_1 |
mov ecx,512/4 |
xor eax,eax |
mov edi,buffer |
cld |
rep stosd ; clear new directory cluster |
pop eax |
sub eax,2 |
mov ecx,[SECTORS_PER_CLUSTER] |
imul eax,ecx |
add eax,[DATA_START] |
mov ebx,buffer |
push eax ; save sector number |
adw_set_empty_directory: |
call hd_write |
cmp [hd_error],0 |
jne adw_not_found_1 |
inc eax ; next sector |
dec ecx |
jnz adw_set_empty_directory |
pop eax |
adw_found: |
pop edi edx ecx |
clc ; free space found |
ret |
adw_not_found_1: |
add esp,4 |
adw_not_found: |
pop edi edx ecx |
stc ; free space not found |
ret |
get_data_cluster: |
;----------------------------------------------------------- |
; input : EAX = cluster |
; EBX = pointer to buffer |
; EDX = # blocks to read in buffer |
; ESI = # blocks to skip over |
; output : if CARRY=0 ok EBX/EDX/ESI updated |
; if CARRY=1 cluster out of range |
; Note : if cluster=0 it's changed to read rootdir |
;----------------------------------------------------------- |
push eax ecx |
mov [fat16_root],0 |
cmp eax,[LAST_CLUSTER] |
ja gdc_error ; too big cluster number, something is wrong |
cmp eax,2 |
jnb gdc_cluster |
mov eax,[ROOT_CLUSTER] ; if cluster < 2 then read rootdir |
cmp [fs_type],16 |
jne gdc_cluster |
mov eax,[ROOT_START] |
mov ecx,[ROOT_SECTORS] ; Note: not cluster size |
mov [fat16_root],1 ; flag for fat16 rootdir |
jmp gdc_read |
gdc_cluster: |
sub eax,2 |
mov ecx,[SECTORS_PER_CLUSTER] |
imul eax,ecx |
add eax,[DATA_START] |
gdc_read: |
test esi,esi ; first wanted block |
je gdcl1 ; yes, skip count is 0 |
dec esi |
jmp gdcl2 |
gdcl1: |
call hd_read |
cmp [hd_error],0 |
jne gdc_error |
add ebx,512 ; update pointer |
dec edx |
gdcl2: |
test edx,edx ; is all read? |
je out_of_read |
inc eax ; next sector |
dec ecx |
jnz gdc_read |
out_of_read: |
pop ecx eax |
clc |
ret |
gdc_error: |
pop ecx eax |
stc |
ret |
set_data_cluster: |
;----------------------------------------------------------- |
; input : EAX = cluster |
; EBX = pointer to buffer |
; output : if CARRY=0 ok |
; if CARRY=1 cluster out of range |
;----------------------------------------------------------- |
push eax ebx edx |
cmp eax,[LAST_CLUSTER] |
ja sdc_error ; too big cluster number, something is wrong |
sub eax,2 |
jb sdc_error ; don't allow rootdir write |
mov edx,[SECTORS_PER_CLUSTER] |
imul eax,edx |
add eax,[DATA_START] |
sdc_write: |
call hd_write |
cmp [hd_error],0 |
jne sdc_error |
add ebx,512 ; update pointer |
inc eax |
dec edx |
jnz sdc_write |
pop edx ebx eax |
clc |
ret |
sdc_error: |
pop edx ebx eax |
stc |
ret |
get_cluster_of_a_path: |
;--------------------------------------------------------- |
; input : EBX = pointer to a path string |
; (example: the path "/files/data/document" become |
; "files......data.......document...0" |
; '.' = space char |
; '0' = char(0) (ASCII=0) !!! ) |
; output : if (CARRY=1) -> ERROR in the PATH |
; if (CARRY=0) -> EAX=cluster |
;--------------------------------------------------------- |
push ebx edx |
mov eax,[ROOT_CLUSTER] |
mov edx,ebx |
search_end_of_path: |
cmp byte [edx],0 |
je found_end_of_path |
inc edx ; '/' |
mov ebx,edx |
call analyze_directory |
jc directory_not_found |
mov eax,[ebx+20-2] ; read the HIGH 16bit cluster field |
mov ax,[ebx+26] ; read the LOW 16bit cluster field |
and eax,[fatMASK] |
add edx,11 ; 8+3 (name+extension) |
jmp search_end_of_path |
found_end_of_path: |
pop edx ebx |
clc ; no errors |
ret |
directory_not_found: |
pop edx ebx |
stc ; errors occour |
ret |
bcd2bin: |
;---------------------------------- |
; input : AL=BCD number (eg. 0x11) |
; output : AH=0 |
; AL=decimal number (eg. 11) |
;---------------------------------- |
xor ah,ah |
shl ax,4 |
shr al,4 |
aad |
ret |
get_date_for_file: |
;----------------------------------------------------- |
; Get date from CMOS and pack day,month,year in AX |
; DATE bits 0..4 : day of month 0..31 |
; 5..8 : month of year 1..12 |
; 9..15 : count of years from 1980 |
;----------------------------------------------------- |
mov al,0x7 ;day |
out 0x70,al |
in al,0x71 |
call bcd2bin |
ror eax,5 |
mov al,0x8 ;month |
out 0x70,al |
in al,0x71 |
call bcd2bin |
ror eax,4 |
mov al,0x9 ;year |
out 0x70,al |
in al,0x71 |
call bcd2bin |
add ax,20 ;because CMOS return only the two last |
;digit (eg. 2000 -> 00 , 2001 -> 01) and we |
rol eax,9 ;need the difference with 1980 (eg. 2001-1980) |
ret |
get_time_for_file: |
;----------------------------------------------------- |
; Get time from CMOS and pack hour,minute,second in AX |
; TIME bits 0..4 : second (the low bit is lost) |
; 5..10 : minute 0..59 |
; 11..15 : hour 0..23 |
;----------------------------------------------------- |
mov al,0x0 ;second |
out 0x70,al |
in al,0x71 |
call bcd2bin |
ror eax,6 |
mov al,0x2 ;minute |
out 0x70,al |
in al,0x71 |
call bcd2bin |
ror eax,6 |
mov al,0x4 ;hour |
out 0x70,al |
in al,0x71 |
call bcd2bin |
rol eax,11 |
ret |
set_current_time_for_entry: |
;----------------------------------------------------- |
; Set current time/date for file entry |
; input : ebx = file entry pointer |
;----------------------------------------------------- |
push eax |
call get_time_for_file ; update files date/time |
mov [ebx+22],ax |
call get_date_for_file |
mov [ebx+24],ax |
pop eax |
ret |
add_disk_free_space: |
;----------------------------------------------------- |
; input : ecx = cluster count |
; Note : negative = remove clusters from free space |
; positive = add clusters to free space |
;----------------------------------------------------- |
test ecx,ecx ; no change |
je add_dfs_no |
cmp [fs_type],32 ; free disk space only used by fat32 |
jne add_dfs_no |
push eax ebx |
mov eax,[ADR_FSINFO] |
mov ebx,fsinfo_buffer |
call hd_read |
cmp [hd_error],0 |
jne add_not_fs |
cmp dword [ebx+0x1fc],0xaa550000 ; check sector id |
jne add_not_fs |
add [ebx+0x1e8],ecx |
call hd_write |
; cmp [hd_error],0 |
; jne add_not_fs |
add_not_fs: |
pop ebx eax |
add_dfs_no: |
ret |
file_write: |
;-------------------------------------------------------------------------- |
; INPUT : user-reg register-in-this meaning symbol-in-this-routine |
; |
; EAX EDI system call to write / |
; EBX EAX (PAR0) pointer to file-name PAR0 |
; EDX ECX (PAR1) pointer to buffer PAR1 |
; ECX EBX (PAR2) file size PAR2 |
; ESI EDX (PAR3) pointer to path PAR3 |
; |
; output : eax = 0 - ok |
; 3 - unknown FS |
; 5 - file not found |
; 8 - disk full |
; 10 - access denied |
;-------------------------------------------------------------------------- |
cmp [fs_type], 16 |
jz fat_ok_for_writing |
cmp [fs_type], 32 |
jz fat_ok_for_writing |
push ERROR_UNKNOWN_FS |
pop eax |
ret |
fat_ok_for_writing: |
; call reserve_hd1 |
pushad |
xor edi,edi ; don't allow directory remove |
call file_delete ; try to delete the file first |
cmp [hd_error],0 |
jne exit_write_access_1 |
test eax,eax |
jz old_deleted ; deleted ok |
cmp eax,ERROR_FILE_NOT_FOUND |
jnz exit_write_access ; it exist but can't delete |
old_deleted: |
mov ebx,PUSHAD_EDX |
call get_cluster_of_a_path |
jnc found_directory_for_writing |
cmp [hd_error],0 |
jne exit_write_access |
exit_writing_with_error: |
popad |
call update_disk ; write all of cache and fat to hd |
cmp [hd_error],0 |
jne exit_write_access_2 |
mov [hd1_status],0 |
mov eax,ERROR_FILE_NOT_FOUND |
ret |
exit_writing_disk_full_clear: |
cmp [hd_error],0 |
jne exit_write_access_1 |
mov eax,[sector_tmp] |
mov ebx,buffer |
call hd_read ; read directory sector |
cmp [hd_error],0 |
jne exit_write_access_1 |
mov edx,[entry_pos] |
mov byte [edx],0xe5 ; mark as deleted |
call hd_write |
cmp [hd_error],0 |
jne exit_write_access_1 |
mov eax,[edx+20-2] ; FAT entry |
mov ax,[edx+26] |
and eax,[fatMASK] |
call clear_cluster_chain |
exit_writing_disk_full: |
cmp [hd_error],0 |
jne exit_write_access_1 |
popad |
call update_disk ; write all of cache and fat to hd |
cmp [hd_error],0 |
jne exit_write_access_2 |
mov [hd1_status],0 |
mov eax,ERROR_DISK_FULL |
ret |
exit_write_access: |
popad |
call update_disk ; write all of cache and fat to hd |
mov [hd1_status],0 |
mov eax,ERROR_ACCESS_DENIED |
ret |
exit_write_access_1: |
popad |
exit_write_access_2: |
mov [hd1_status],0 |
mov eax,ERROR_ACCESS_DENIED |
ret |
found_directory_for_writing: |
call analyze_directory_to_write |
jc exit_writing_disk_full |
mov [sector_tmp],eax |
mov [entry_pos],ebx |
push eax ; save directory sector |
mov eax,2 |
call get_free_FAT |
mov [cluster],eax ; first free cluster |
pop eax |
jc exit_writing_disk_full |
mov esi,PUSHAD_EAX ; file name |
mov edi,ebx ; pointer in buffer |
mov ecx,11 |
cld |
rep movsb |
mov esi,PUSHAD_EBX ; file size (bytes left) |
mov [ebx+28],esi ; file size |
mov ecx,[cluster] |
mov [ebx+26],cx ; 16 bits low of cluster |
shr ecx,16 |
mov [ebx+20],cx ; 16 bits high of cluster (=0 fat16) |
mov byte [ebx+11],0x20 ; attribute = archive |
call set_current_time_for_entry |
mov ebx,buffer ; save the directory name,length,cluster |
call hd_write |
cmp [hd_error],0 |
jne exit_write_access_1 |
imul edi,[SECTORS_PER_CLUSTER],512 ; edi = cluster size in bytes |
xor ecx,ecx ; cluster count |
mov ebx,PUSHAD_ECX ; ebx = buffer |
hd_new_block_write: |
mov eax,[cluster] ; eax = block |
call set_data_cluster |
cmp [hd_error],0 |
jne exit_write_access_1 |
sub esi,edi ; sub wrote bytes |
jbe file_saved_OK ; end if all done |
add ebx,edi ; update buffer position |
inc eax |
call get_free_FAT ; next free in FAT |
jc exit_writing_disk_full_clear |
mov edx,eax |
xchg eax,[cluster] ; get old cluster and save new cluster |
call set_FAT ; add it in cluster chain |
cmp [hd_error],0 |
jne exit_write_access_1 |
dec ecx ; update cluster count |
jmp hd_new_block_write |
file_saved_OK: |
mov edx,[fatEND] ; new end for cluster chain |
call set_FAT |
cmp [hd_error],0 |
jne exit_write_access_1 |
dec ecx ; update cluster count |
call add_disk_free_space ; remove clusters from free disk space |
cmp [hd_error],0 |
jne exit_write_access_1 |
popad |
call update_disk ; write all of cache and fat to hd |
cmp [hd_error],0 |
jne exit_write_access_2 |
mov [hd1_status],0 |
xor eax,eax |
ret |
file_read: |
;-------------------------------------------------------------------------- |
; INPUT : user-register register-in-this meaning symbol-in-this |
; |
; EAX EDI system call to write / |
; EBX EAX (PAR0) pointer to file-name PAR0 |
; EDX ECX (PAR1) pointer to buffer PAR1 |
; ECX EBX (PAR2) vt file blocks to read PAR2 |
; ESI EDX (PAR3) pointer to path PAR3 |
; EDI ESI vt first 512 block to read |
; EDI if 0 - read root |
; |
; output : eax = 0 - ok |
; 3 - unknown FS |
; 5 - file not found |
; 6 - end of file |
; 9 - fat table corrupted |
; 10 - access denied |
; ebx = size of file/directory |
;-------------------------------------------------------------------------- |
cmp [fs_type], 16 |
jz fat_ok_for_reading |
cmp [fs_type], 32 |
jz fat_ok_for_reading |
xor ebx,ebx |
mov eax,ERROR_UNKNOWN_FS |
mov [hd1_status], ebx |
ret |
fat_ok_for_reading: |
; call reserve_hd1 |
pushad |
mov ebx,edx |
call get_cluster_of_a_path |
jc file_to_read_not_found |
test edi,edi ; read rootdir |
jne no_read_root |
xor eax,eax |
call get_dir_size ; return rootdir size |
cmp [hd_error],0 |
jne file_access_denied |
mov [file_size],eax |
mov eax,[ROOT_CLUSTER] |
jmp file_read_start |
no_read_root: |
mov ebx,PUSHAD_EAX ; file name |
call analyze_directory |
jc file_to_read_not_found |
mov eax,[ebx+28] ; file size |
test byte [ebx+11],0x10 ; is it directory? |
jz read_set_size ; no |
mov eax,[ebx+20-2] ; FAT entry |
mov ax,[ebx+26] |
and eax,[fatMASK] |
call get_dir_size |
cmp [hd_error],0 |
jne file_access_denied |
read_set_size: |
mov [file_size],eax |
mov eax,[ebx+20-2] ; FAT entry |
mov ax,[ebx+26] |
and eax,[fatMASK] |
file_read_start: |
mov ebx,PUSHAD_ECX ; pointer to buffer |
mov edx,PUSHAD_EBX ; file blocks to read |
mov esi,PUSHAD_ESI ; first 512 block to read |
file_read_new_cluster: |
call get_data_cluster |
jc file_read_eof ; end of file or cluster out of range |
test edx,edx ; is all read? |
je file_read_OK ; yes |
call get_FAT ; get next cluster |
cmp [hd_error],0 |
jne file_access_denied |
cmp eax,[fatRESERVED] ; end of file |
jnb file_read_eof |
cmp eax,2 ; incorrect fat chain |
jnb file_read_new_cluster |
popad |
mov [hd1_status],0 |
mov ebx,[file_size] |
mov eax,ERROR_FAT_TABLE |
ret |
file_read_eof: |
cmp [hd_error],0 |
jne file_access_denied |
popad |
mov [hd1_status],0 |
mov ebx,[file_size] |
mov eax,ERROR_END_OF_FILE |
ret |
file_read_OK: |
popad |
mov [hd1_status],0 |
mov ebx,[file_size] |
xor eax,eax |
ret |
file_to_read_not_found: |
cmp [hd_error],0 |
jne file_access_denied |
popad |
mov [hd1_status],0 |
xor ebx,ebx |
mov eax,ERROR_FILE_NOT_FOUND |
ret |
file_access_denied: |
popad |
mov [hd1_status],0 |
xor ebx,ebx |
mov eax,ERROR_ACCESS_DENIED |
ret |
get_dir_size: |
;----------------------------------------------------- |
; input : eax = first cluster (0=rootdir) |
; output : eax = directory size in bytes |
;----------------------------------------------------- |
push edx |
xor edx,edx ; count of directory clusters |
test eax,eax |
jnz dir_size_next |
mov eax,[ROOT_SECTORS] |
shl eax,9 ; fat16 rootdir size in bytes |
cmp [fs_type],16 |
je dir_size_ret |
mov eax,[ROOT_CLUSTER] |
dir_size_next: |
cmp eax,2 ; incorrect fat chain |
jb dir_size_end |
cmp eax,[fatRESERVED] ; end of directory |
ja dir_size_end |
call get_FAT ; get next cluster |
cmp [hd_error],0 |
jne dir_size_ret |
inc edx |
jmp dir_size_next |
dir_size_end: |
imul eax,[SECTORS_PER_CLUSTER],512 ; cluster size in bytes |
imul eax,edx |
dir_size_ret: |
pop edx |
ret |
file_delete: |
;----------------------------------------------------- |
; input : eax = file/directory name |
; edx = path |
; edi = 1 - allow directory remove else don't remove directory |
; output : eax = 0 - ok |
; 3 - unknown FS |
; 5 - file not found |
; 10 - access denied |
;----------------------------------------------------- |
cmp [fs_type], 16 |
jz file_del_fat_ok |
cmp [fs_type], 32 |
jz file_del_fat_ok |
push ERROR_UNKNOWN_FS |
pop eax |
ret |
file_del_fat_ok: |
pushad |
mov ebx,edx |
call get_cluster_of_a_path |
jc file_to_delete_not_found |
mov ebx,PUSHAD_EAX ; file/directory name |
call analyze_directory |
jc file_to_delete_not_found |
test byte [ebx+11],0x10 ; is it directory? |
jnz delete_no_access |
delete_notdir: |
call delete_entry_name |
cmp [hd_error],0 |
jne delete_no_access |
mov eax,ecx ; first cluster of file |
call clear_cluster_chain |
cmp [hd_error],0 |
jne delete_no_access |
popad |
xor eax,eax |
ret |
delete_no_access_1: |
add esp,4 |
delete_no_access: |
popad |
mov eax,ERROR_ACCESS_DENIED |
ret |
file_to_delete_not_found: |
cmp [hd_error],0 |
jne delete_no_access |
popad |
mov eax,ERROR_FILE_NOT_FOUND |
ret |
clear_cluster_chain: |
;----------------------------------------------------- |
; input : eax = first cluster |
;----------------------------------------------------- |
push eax ecx edx |
xor ecx,ecx ; cluster count |
clean_new_chain: |
cmp eax,[LAST_CLUSTER] ; end of file |
ja delete_OK |
cmp eax,2 ; unfinished fat chain or zero length file |
jb delete_OK |
cmp eax,[ROOT_CLUSTER] ; don't remove root cluster |
jz delete_OK |
xor edx,edx |
call set_FAT ; clear fat entry |
cmp [hd_error],0 |
jne access_denied_01 |
inc ecx ; update cluster count |
mov eax,edx ; old cluster |
jmp clean_new_chain |
delete_OK: |
call add_disk_free_space ; add clusters to free disk space |
access_denied_01: |
pop edx ecx eax |
ret |
delete_entry_name: |
;----------------------------------------------------- |
; input : eax = directory sector |
; ebx = directory pointer in buffer |
; longname_sec = 2 previous directory sectors |
; output : ecx = first cluster |
; change : eax,ebx,edx |
;----------------------------------------------------- |
mov byte [ebx],0xe5 |
mov ecx,[ebx+20-2] ; first cluster of file |
mov cx,[ebx+26] ; 0 length files start cluster = 0 |
and ecx,[fatMASK] |
delete_empty: |
sub ebx,32 |
cmp ebx,buffer |
jnb delete_test_long |
mov ebx,buffer |
call hd_write ; write directory sector back |
cmp [hd_error],0 |
jne delete_name_end |
xor eax,eax |
xchg eax,[longname_sec2] |
xchg eax,[longname_sec1] |
test eax,eax ; is there previous directory sector? |
jz delete_name_end ; no |
mov ebx,buffer |
call hd_read ; read previous sector |
cmp [hd_error],0 |
jne delete_name_end |
mov ebx,buffer+0x1e0 ; start from last entry |
delete_test_long: |
mov dh,[ebx+11] ; file attribute |
and dh,0xf |
cmp dh,0xf |
jne delete_write_buffer |
cmp byte [ebx],0x40 ; end of long dir entry? |
mov byte [ebx],0xe5 |
jb delete_empty |
delete_write_buffer: |
mov ebx,buffer |
call hd_write ; write directory sector back |
delete_name_end: |
ret |
get_hd_info: |
;----------------------------------------------------------- |
; output : eax = 0 - ok |
; 3 - unknown FS |
; 10 - access denied |
; edx = cluster size in bytes |
; ebx = total clusters on disk |
; ecx = free clusters on disk |
;----------------------------------------------------------- |
cmp [fs_type], 16 |
jz info_fat_ok |
cmp [fs_type], 32 |
jz info_fat_ok |
xor edx,edx |
xor ebx,ebx |
xor ecx,ecx |
mov eax,ERROR_UNKNOWN_FS |
ret |
info_fat_ok: |
; call reserve_hd1 |
xor ecx,ecx ; count of free clusters |
mov eax,2 |
mov ebx,[LAST_CLUSTER] |
info_cluster: |
push eax |
call get_FAT ; get cluster info |
cmp [hd_error],0 |
jne info_access_denied |
test eax,eax ; is it free? |
jnz info_used ; no |
inc ecx |
info_used: |
pop eax |
inc eax |
cmp eax,ebx ; is above last cluster? |
jbe info_cluster ; no. test next cluster |
dec ebx ; cluster count |
imul edx,[SECTORS_PER_CLUSTER],512 ; cluster size in bytes |
mov [hd1_status],0 |
xor eax,eax |
ret |
info_access_denied: |
add esp,4 |
xor edx,edx |
xor ebx,ebx |
xor ecx,ecx |
mov eax,ERROR_ACCESS_DENIED |
ret |
update_disk: |
;----------------------------------------------------------- |
; write changed fat and cache to disk |
;----------------------------------------------------------- |
cmp [fat_change],0 ; is fat changed? |
je upd_no_change |
call write_fat_sector |
cmp [hd_error],0 |
jne update_disk_acces_denied |
upd_no_change: |
call write_cache |
update_disk_acces_denied: |
ret |
read_hd_file: |
;----------------------------------------------------------------- |
; |
; Converting old reading function for hd-application start. |
; |
; IN: |
; |
; eax - pointer to file (0 = read only first sector of drive: eg 'label') |
; ebx - file lenght |
; ecx - start 512 byte block number |
; edx - number of blocks to read |
; esi - pointer to return/work area (atleast 20 000 bytes) |
; |
; For new read function |
; |
; EAX (PAR0) pointer to file-name |
; ECX (PAR1) pointer to buffer |
; EBX (PAR2) vt file blocks to read |
; EDX (PAR3) pointer to path |
; ESI vt first 512 block to read |
; EDI if 0 - return root |
;-------------------------------------------------------------------------- |
push ecx esi edi |
mov esi,eax |
mov edi,startpath |
mov ecx,250 |
cld |
rep movsb |
pop edi esi ecx |
mov eax,startpath |
mov [eax+ebx-12],byte 0 |
push eax ebx ecx edx esi |
pop ecx ; pointer to buffer |
add ecx,1024 |
pop ebx ; number of blocks to read |
pop esi ; first block to read |
dec esi |
pop eax ; file length |
pop edx ; pointer to path |
mov edi,12 |
lea eax,[eax+edx-12+1] |
call file_read |
ret |
; \begin{diamond} |
hd_find_lfn: |
; in: esi->name |
; out: CF=1 - file not found |
; else CF=0 and edi->direntry, eax=sector |
; destroys eax |
push esi edi |
push 0 |
push 0 |
push fat16_root_first |
push fat16_root_next |
mov eax, [ROOT_CLUSTER] |
cmp [fs_type], 32 |
jz .fat32 |
.loop: |
call fat_find_lfn |
jc .notfound |
cmp byte [esi], 0 |
jz .found |
test byte [edi+11], 10h |
jz .notfound |
and dword [esp+12], 0 |
mov eax, [edi+20-2] |
mov ax, [edi+26] ; cluster |
.fat32: |
mov [esp+8], eax |
mov dword [esp+4], fat_notroot_first |
mov dword [esp], fat_notroot_next |
jmp .loop |
.notfound: |
add esp, 16 |
pop edi esi |
stc |
ret |
.found: |
lea eax, [esp+8] |
cmp dword [eax], 0 |
jz .root |
call fat_get_sector |
jmp .cmn |
.root: |
mov eax, [eax+4] |
add eax, [ROOT_START] |
.cmn: |
add esp, 20 ; CF=0 |
pop esi |
ret |
;---------------------------------------------------------------- |
; |
; fs_HdRead - LFN variant for reading 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 |
; |
;-------------------------------------------------------------- |
fs_HdRead: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdRead |
or ebx, -1 |
mov eax, ERROR_UNKNOWN_FS |
ret |
@@: |
push edi |
cmp byte [esi], 0 |
jnz @f |
.noaccess: |
pop edi |
.noaccess_2: |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.noaccess_3: |
add esp,4 |
.noaccess_1: |
add esp,4 |
.noaccess_4: |
add esp,4*5 |
jmp .noaccess_2 |
@@: |
call hd_find_lfn |
jnc .found |
pop edi |
cmp [hd_error],0 |
jne .noaccess_2 |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
test byte [edi+11], 0x10 ; do not allow read directories |
jnz .noaccess |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
mov eax, 6 |
pop edi |
ret |
@@: |
mov ebx, [ebx] |
.l1: |
push ecx edx |
push 0 |
mov eax, [edi+28] |
sub eax, ebx |
jb .eof |
cmp eax, ecx |
jae @f |
mov ecx, eax |
mov byte [esp], 6 |
@@: |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data |
.new_cluster: |
jecxz .new_sector |
test eax, eax |
jz .eof |
cmp eax, [fatRESERVED] |
jae .eof |
mov [cluster_tmp], eax |
dec eax |
dec eax |
mov edi, [SECTORS_PER_CLUSTER] |
imul eax, edi |
add eax, [DATA_START] |
.new_sector: |
test ecx, ecx |
jz .done |
sub ebx, 512 |
jae .skip |
add ebx, 512 |
jnz .force_buf |
cmp ecx, 512 |
jb .force_buf |
; we may read directly to given buffer |
push ebx |
mov ebx, edx |
call hd_read |
cmp [hd_error],0 |
jne .noaccess_1 |
pop ebx |
add edx, 512 |
sub ecx, 512 |
jmp .skip |
.force_buf: |
; we must read sector to temporary buffer and then copy it to destination |
push eax ebx |
mov ebx, buffer |
call hd_read |
cmp [hd_error],0 |
jne .noaccess_3 |
mov eax, ebx |
pop ebx |
add eax, ebx |
push ecx |
add ecx, ebx |
cmp ecx, 512 |
jbe @f |
mov ecx, 512 |
@@: |
sub ecx, ebx |
mov ebx, edx |
call memmove |
add edx, ecx |
sub [esp], ecx |
pop ecx |
pop eax |
xor ebx, ebx |
.skip: |
inc eax |
dec edi |
jnz .new_sector |
mov eax, [cluster_tmp] |
call get_FAT |
cmp [hd_error],0 |
jne .noaccess_4 |
jmp .new_cluster |
.done: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx ecx |
sub ebx, edx |
jmp .reteof |
;---------------------------------------------------------------- |
; |
; fs_HdReadFolder - LFN variant for reading 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 |
; |
;-------------------------------------------------------------- |
fs_HdReadFolder: |
cmp [fs_type], 1 |
jz ntfs_HdReadFolder |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
push ERROR_UNSUPPORTED_FS |
pop eax |
or ebx, -1 |
ret |
@@: |
mov eax, [ROOT_CLUSTER] |
push edi |
cmp byte [esi], 0 |
jz .doit |
call hd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
test byte [edi+11], 0x10 ; do not allow read files |
jnz .found_dir |
pop edi |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
mov eax, [edi+20-2] |
mov ax, [edi+26] ; eax=cluster |
.doit: |
push esi ecx |
push ebp |
sub esp, 262*2 ; reserve space for LFN |
mov ebp, esp |
push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE name |
mov ebx, [ebx] |
; init header |
push eax ecx |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
pop ecx eax |
mov byte [edx], 1 ; version |
mov esi, edi ; esi points to BDFE |
.new_cluster: |
mov [cluster_tmp], eax |
test eax, eax |
jnz @f |
cmp [fs_type], 32 |
jz .notfound |
mov eax, [ROOT_START] |
push [ROOT_SECTORS] |
push ebx |
jmp .new_sector |
@@: |
dec eax |
dec eax |
imul eax, [SECTORS_PER_CLUSTER] |
push [SECTORS_PER_CLUSTER] |
add eax, [DATA_START] |
push ebx |
.new_sector: |
mov ebx, buffer |
mov edi, ebx |
call hd_read |
cmp [hd_error], 0 |
jnz .notfound2 |
add ebx, 512 |
push eax |
.l1: |
call fat_get_name |
jc .l2 |
cmp byte [edi+11], 0xF |
jnz .do_bdfe |
add edi, 0x20 |
cmp edi, ebx |
jb .do_bdfe |
pop eax |
inc eax |
dec dword [esp+4] |
jnz @f |
mov eax, [cluster_tmp] |
test eax, eax |
jz .done |
call get_FAT |
cmp [hd_error], 0 |
jnz .notfound2 |
cmp eax, 2 |
jb .done |
cmp eax, [fatRESERVED] |
jae .done |
push eax |
mov eax, [SECTORS_PER_CLUSTER] |
mov [esp+8], eax |
pop eax |
mov [cluster_tmp], eax |
dec eax |
dec eax |
imul eax, [SECTORS_PER_CLUSTER] |
add eax, [DATA_START] |
@@: |
mov ebx, buffer |
mov edi, ebx |
call hd_read |
cmp [hd_error], 0 |
jnz .notfound2 |
add ebx, 512 |
push eax |
.do_bdfe: |
inc dword [edx+8] ; new file found |
dec dword [esp+4] |
jns .l2 |
dec ecx |
js .l2 |
inc dword [edx+4] ; new file block copied |
call fat_entry_to_bdfe |
.l2: |
add edi, 0x20 |
cmp edi, ebx |
jb .l1 |
pop eax |
inc eax |
dec dword [esp+4] |
jnz .new_sector |
mov eax, [cluster_tmp] |
test eax, eax |
jz .done |
call get_FAT |
cmp [hd_error], 0 |
jnz .notfound2 |
cmp eax, 2 |
jb .done |
cmp eax, [fatRESERVED] |
jae .done |
push eax |
mov eax, [SECTORS_PER_CLUSTER] |
mov [esp+8], eax |
pop eax |
pop ebx |
add esp, 4 |
jmp .new_cluster |
.notfound2: |
add esp, 8 |
.notfound: |
add esp, 262*2+4 |
pop ebp ecx esi edi |
mov eax, ERROR_FILE_NOT_FOUND |
or ebx, -1 |
ret |
.done: |
add esp, 262*2+4+8 |
pop ebp |
mov ebx, [edx+4] |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
pop ecx esi edi |
ret |
fat16_root_next: |
cmp edi, buffer+0x200-0x20 |
jae fat16_root_next_sector |
add edi, 0x20 |
ret ; CF=0 |
fat16_root_next_sector: |
; read next sector |
push [longname_sec2] |
pop [longname_sec1] |
push ecx |
mov ecx, [eax+4] |
push ecx |
add ecx, [ROOT_START] |
mov [longname_sec2], ecx |
pop ecx |
inc ecx |
mov [eax+4], ecx |
cmp ecx, [ROOT_SECTORS] |
pop ecx |
jae fat16_root_first.readerr |
fat16_root_first: |
mov eax, [eax+4] |
add eax, [ROOT_START] |
push ebx |
mov edi, buffer |
mov ebx, edi |
call hd_read |
pop ebx |
cmp [hd_error], 0 |
jnz .readerr |
ret ; CF=0 |
.readerr: |
stc |
ret |
fat16_root_begin_write: |
push edi eax |
call fat16_root_first |
pop eax edi |
ret |
fat16_root_end_write: |
pusha |
mov eax, [eax+4] |
add eax, [ROOT_START] |
mov ebx, buffer |
call hd_write |
popa |
ret |
fat16_root_next_write: |
cmp edi, buffer+0x200 |
jae @f |
ret |
@@: |
call fat16_root_end_write |
jmp fat16_root_next_sector |
fat16_root_extend_dir: |
stc |
ret |
fat_notroot_next: |
cmp edi, buffer+0x200-0x20 |
jae fat_notroot_next_sector |
add edi, 0x20 |
ret ; CF=0 |
fat_notroot_next_sector: |
push [longname_sec2] |
pop [longname_sec1] |
push eax |
call fat_get_sector |
mov [longname_sec2], eax |
pop eax |
push ecx |
mov ecx, [eax+4] |
inc ecx |
cmp ecx, [SECTORS_PER_CLUSTER] |
jae fat_notroot_next_cluster |
mov [eax+4], ecx |
jmp @f |
fat_notroot_next_cluster: |
push eax |
mov eax, [eax] |
call get_FAT |
mov ecx, eax |
pop eax |
cmp [hd_error], 0 |
jnz fat_notroot_next_err |
cmp ecx, [fatRESERVED] |
jae fat_notroot_next_err |
mov [eax], ecx |
and dword [eax+4], 0 |
@@: |
pop ecx |
fat_notroot_first: |
call fat_get_sector |
push ebx |
mov edi, buffer |
mov ebx, edi |
call hd_read |
pop ebx |
cmp [hd_error], 0 |
jnz @f |
ret ; CF=0 |
fat_notroot_next_err: |
pop ecx |
@@: |
stc |
ret |
fat_notroot_begin_write: |
push eax edi |
call fat_notroot_first |
pop edi eax |
ret |
fat_notroot_end_write: |
call fat_get_sector |
push ebx |
mov ebx, buffer |
call hd_write |
pop ebx |
ret |
fat_notroot_next_write: |
cmp edi, buffer+0x200 |
jae @f |
ret |
@@: |
push eax |
call fat_notroot_end_write |
pop eax |
jmp fat_notroot_next_sector |
fat_notroot_extend_dir: |
push eax |
mov eax, [eax] |
call get_free_FAT |
jnc .found |
pop eax |
ret ; CF=1 |
.found: |
push edx |
mov edx, [fatEND] |
call set_FAT |
mov edx, eax |
mov eax, [esp+4] |
mov eax, [eax] |
push edx |
call set_FAT |
pop edx |
cmp [hd_error], 0 |
jz @f |
pop edx |
pop eax |
stc |
ret |
@@: |
push ecx |
or ecx, -1 |
call add_disk_free_space |
; zero new cluster |
mov ecx, 512/4 |
mov edi, buffer |
push edi |
xor eax, eax |
rep stosd |
pop edi |
pop ecx |
mov eax, [esp+4] |
mov [eax], edx |
and dword [eax+4], 0 |
pop edx |
mov eax, [eax] |
dec eax |
dec eax |
push ebx ecx |
mov ecx, [SECTORS_PER_CLUSTER] |
imul eax, ecx |
add eax, [DATA_START] |
mov ebx, edi |
@@: |
call hd_write |
inc eax |
loop @b |
pop ecx ebx eax |
clc |
ret |
fat_get_sector: |
push ecx |
mov ecx, [eax] |
dec ecx |
dec ecx |
imul ecx, [SECTORS_PER_CLUSTER] |
add ecx, [DATA_START] |
add ecx, [eax+4] |
mov eax, ecx |
pop ecx |
ret |
;---------------------------------------------------------------- |
; |
; fs_HdRewrite - LFN variant for writing 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 |
; |
;-------------------------------------------------------------- |
fshrad: |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
fshrfs: |
mov eax, ERROR_UNKNOWN_FS |
xor ebx, ebx |
ret |
fs_HdCreateFolder: |
mov al, 1 |
jmp fs_HdRewrite.common |
fs_HdRewrite: |
xor eax, eax |
.common: |
cmp [fs_type], 1 |
jz ntfs_HdRewrite |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jnz fshrfs |
@@: |
cmp byte [esi], 0 |
jz fshrad |
pushad |
xor ebp, ebp |
push esi |
@@: |
lodsb |
test al, al |
jz @f |
cmp al, '/' |
jnz @b |
lea ebp, [esi-1] |
jmp @b |
@@: |
pop esi |
test ebp, ebp |
jnz .noroot |
mov ebp, [ROOT_CLUSTER] |
cmp [fs_type], 32 |
jz .pushnotroot |
push fat16_root_extend_dir |
push fat16_root_end_write |
push fat16_root_next_write |
push fat16_root_begin_write |
xor ebp, ebp |
push ebp |
push ebp |
push fat16_root_first |
push fat16_root_next |
jmp .common1 |
.noroot: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [ebp+1], 0 |
jz .ret1 |
; check existence |
mov byte [ebp], 0 |
call hd_find_lfn |
mov byte [ebp], '/' |
lea esi, [ebp+1] |
jnc @f |
mov eax, ERROR_FILE_NOT_FOUND |
.ret1: |
mov [esp+28], eax |
popad |
xor ebx, ebx |
ret |
@@: |
test byte [edi+11], 0x10 ; must be directory |
mov eax, ERROR_ACCESS_DENIED |
jz .ret1 |
mov ebp, [edi+20-2] |
mov bp, [edi+26] ; ebp=cluster |
mov eax, ERROR_FAT_TABLE |
cmp ebp, 2 |
jb .ret1 |
.pushnotroot: |
push fat_notroot_extend_dir |
push fat_notroot_end_write |
push fat_notroot_next_write |
push fat_notroot_begin_write |
push 0 |
push ebp |
push fat_notroot_first |
push fat_notroot_next |
.common1: |
call fat_find_lfn |
jc .notfound |
; found |
test byte [edi+11], 10h |
jz .exists_file |
; found directory; if we are creating directory, return OK, |
; if we are creating file, say "access denied" |
add esp, 32 |
popad |
test al, al |
mov eax, ERROR_ACCESS_DENIED |
jz @f |
mov al, 0 |
@@: |
xor ebx, ebx |
ret |
.exists_file: |
; found file; if we are creating directory, return "access denied", |
; if we are creating file, delete existing file and continue |
cmp byte [esp+32+28], 0 |
jz @f |
add esp, 32 |
popad |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
@@: |
; delete FAT chain |
push edi |
xor eax, eax |
mov dword [edi+28], eax ; zero size |
xor ecx, ecx |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov word [edi+20], cx |
mov word [edi+26], cx |
test eax, eax |
jz .done1 |
@@: |
cmp eax, [fatRESERVED] |
jae .done1 |
push edx |
xor edx, edx |
call set_FAT |
mov eax, edx |
pop edx |
inc ecx |
jmp @b |
.done1: |
pop edi |
call get_time_for_file |
mov [edi+22], ax |
call get_date_for_file |
mov [edi+24], ax |
mov [edi+18], ax |
or byte [edi+11], 20h ; set 'archive' attribute |
jmp .doit |
.notfound: |
; file is not found; generate short name |
call fat_name_is_legal |
jc @f |
add esp, 32 |
popad |
mov eax, ERROR_FILE_NOT_FOUND |
xor ebx, ebx |
ret |
@@: |
sub esp, 12 |
mov edi, esp |
call fat_gen_short_name |
.test_short_name_loop: |
push esi edi ecx |
mov esi, edi |
lea eax, [esp+12+12+8] |
mov [eax], ebp |
and dword [eax+4], 0 |
call dword [eax-4] |
jc .found |
.test_short_name_entry: |
cmp byte [edi+11], 0xF |
jz .test_short_name_cont |
mov ecx, 11 |
push esi edi |
repz cmpsb |
pop edi esi |
jz .short_name_found |
.test_short_name_cont: |
lea eax, [esp+12+12+8] |
call dword [eax-8] |
jnc .test_short_name_entry |
jmp .found |
.short_name_found: |
pop ecx edi esi |
call fat_next_short_name |
jnc .test_short_name_loop |
.disk_full: |
add esp, 12+32 |
popa |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.found: |
pop ecx edi esi |
; now find space in directory |
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~' |
mov al, '~' |
push ecx edi |
mov ecx, 8 |
repnz scasb |
push 1 |
pop eax ; 1 entry |
jnz .notilde |
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total |
xor eax, eax |
@@: |
cmp byte [esi], 0 |
jz @f |
inc esi |
inc eax |
jmp @b |
@@: |
sub esi, eax |
add eax, 12+13 |
mov ecx, 13 |
push edx |
cdq |
div ecx |
pop edx |
.notilde: |
push -1 |
push -1 |
push -1 |
; find <eax> successive entries in directory |
xor ecx, ecx |
push eax |
lea eax, [esp+16+8+12+8] |
mov [eax], ebp |
and dword [eax+4], 0 |
call dword [eax-4] |
pop eax |
jnc .scan_dir |
.fsfrfe3: |
add esp, 12+8+12+32 |
popad |
mov eax, 11 |
xor ebx, ebx |
ret |
.scan_dir: |
cmp byte [edi], 0 |
jz .free |
cmp byte [edi], 0xE5 |
jz .free |
xor ecx, ecx |
.scan_cont: |
push eax |
lea eax, [esp+16+8+12+8] |
call dword [eax-8] |
pop eax |
jnc .scan_dir |
cmp [hd_error], 0 |
jnz .fsfrfe3 |
push eax |
lea eax, [esp+16+8+12+8] |
call dword [eax+20] ; extend directory |
pop eax |
jnc .scan_dir |
add esp, 12+8+12+32 |
popad |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.free: |
test ecx, ecx |
jnz @f |
mov [esp], edi |
mov ecx, [esp+12+8+12+8] |
mov [esp+4], ecx |
mov ecx, [esp+12+8+12+12] |
mov [esp+8], ecx |
xor ecx, ecx |
@@: |
inc ecx |
cmp ecx, eax |
jb .scan_cont |
; found! |
; calculate name checksum |
push esi ecx |
mov esi, [esp+8+12] |
mov ecx, 11 |
xor eax, eax |
@@: |
ror al, 1 |
add al, [esi] |
inc esi |
loop @b |
pop ecx esi |
pop edi |
pop dword [esp+8+12+12] |
pop dword [esp+8+12+12] |
; edi points to first entry in free chunk |
dec ecx |
jz .nolfn |
push esi |
push eax |
lea eax, [esp+8+8+12+8] |
call dword [eax+8] ; begin write |
mov al, 40h |
.writelfn: |
or al, cl |
mov esi, [esp+4] |
push ecx |
dec ecx |
imul ecx, 13 |
add esi, ecx |
stosb |
mov cl, 5 |
call fs_RamdiskRewrite.read_symbols |
mov ax, 0xF |
stosw |
mov al, [esp+4] |
stosb |
mov cl, 6 |
call fs_RamdiskRewrite.read_symbols |
xor eax, eax |
stosw |
mov cl, 2 |
call fs_RamdiskRewrite.read_symbols |
pop ecx |
lea eax, [esp+8+8+12+8] |
call dword [eax+12] ; next write |
xor eax, eax |
loop .writelfn |
pop eax |
pop esi |
; lea eax, [esp+8+12+8] |
; call dword [eax+16] ; end write |
.nolfn: |
xchg esi, [esp] |
mov ecx, 11 |
rep movsb |
mov word [edi], 20h ; attributes |
sub edi, 11 |
pop esi ecx |
add esp, 12 |
mov byte [edi+13], 0 ; tenths of a second at file creation time |
call get_time_for_file |
mov [edi+14], ax ; creation time |
mov [edi+22], ax ; last write time |
call get_date_for_file |
mov [edi+16], ax ; creation date |
mov [edi+24], ax ; last write date |
mov [edi+18], ax ; last access date |
xor ecx, ecx |
mov word [edi+20], cx ; high word of cluster |
mov word [edi+26], cx ; low word of cluster - to be filled |
mov dword [edi+28], ecx ; file size - to be filled |
cmp byte [esp+32+28], cl |
jz .doit |
; create directory |
mov byte [edi+11], 10h ; attributes: folder |
mov edx, edi |
lea eax, [esp+8] |
call dword [eax+16] ; flush directory |
push ecx |
mov ecx, [SECTORS_PER_CLUSTER] |
shl ecx, 9 |
jmp .doit2 |
.doit: |
lea eax, [esp+8] |
call dword [eax+16] ; flush directory |
push ecx |
mov ecx, [esp+4+32+24] |
.doit2: |
push ecx |
push edi |
mov esi, edx |
test ecx, ecx |
jz .done |
mov eax, 2 |
call get_free_FAT |
jc .diskfull |
push eax |
mov [edi+26], ax |
shr eax, 16 |
mov [edi+20], ax |
lea eax, [esp+16+8] |
call dword [eax+16] ; flush directory |
pop eax |
push edx |
mov edx, [fatEND] |
call set_FAT |
pop edx |
.write_cluster: |
push eax |
dec eax |
dec eax |
mov ebp, [SECTORS_PER_CLUSTER] |
imul eax, ebp |
add eax, [DATA_START] |
; write data |
.write_sector: |
cmp byte [esp+16+32+28], 0 |
jnz .writedir |
mov ecx, 512 |
cmp dword [esp+8], ecx |
jb .writeshort |
; we can write directly from given buffer |
mov ebx, esi |
add esi, ecx |
jmp .writecommon |
.writeshort: |
mov ecx, [esp+8] |
push ecx |
mov edi, buffer |
mov ebx, edi |
rep movsb |
.writedircont: |
mov ecx, buffer+0x200 |
sub ecx, edi |
push eax |
xor eax, eax |
rep stosb |
pop eax |
pop ecx |
.writecommon: |
call hd_write |
cmp [hd_error], 0 |
jnz .writeerr |
inc eax |
sub dword [esp+8], ecx |
jz .writedone |
dec ebp |
jnz .write_sector |
; allocate new cluster |
pop eax |
mov ecx, eax |
call get_free_FAT |
jc .diskfull |
push edx |
mov edx, [fatEND] |
call set_FAT |
xchg eax, ecx |
mov edx, ecx |
call set_FAT |
pop edx |
xchg eax, ecx |
jmp .write_cluster |
.diskfull: |
mov eax, ERROR_DISK_FULL |
jmp .ret |
.writeerr: |
pop eax |
sub esi, ecx |
mov eax, 11 |
jmp .ret |
.writedone: |
pop eax |
.done: |
xor eax, eax |
.ret: |
pop edi ecx |
mov ebx, esi |
sub ebx, edx |
pop ebp |
mov [esp+32+28], eax |
lea eax, [esp+8] |
call dword [eax+8] |
mov [edi+28], ebx |
call dword [eax+16] |
mov [esp+32+16], ebx |
lea eax, [ebx+511] |
shr eax, 9 |
mov ecx, [SECTORS_PER_CLUSTER] |
lea eax, [eax+ecx-1] |
xor edx, edx |
div ecx |
mov ecx, ebp |
sub ecx, eax |
call add_disk_free_space |
add esp, 32 |
call update_disk |
popad |
ret |
.writedir: |
push 512 |
mov edi, buffer |
mov ebx, edi |
mov ecx, [SECTORS_PER_CLUSTER] |
shl ecx, 9 |
cmp ecx, [esp+12] |
jnz .writedircont |
dec dword [esp+16] |
push esi |
mov ecx, 32/4 |
rep movsd |
pop esi |
mov dword [edi-32], '. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
push esi |
mov ecx, 32/4 |
rep movsd |
pop esi |
mov dword [edi-32], '.. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
mov ecx, [esp+20+8] |
cmp ecx, [ROOT_CLUSTER] |
jnz @f |
xor ecx, ecx |
@@: |
mov word [edi-32+26], cx |
shr ecx, 16 |
mov [edi-32+20], cx |
jmp .writedircont |
;---------------------------------------------------------------- |
; |
; fs_HdWrite - LFN variant for writing to 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 |
; |
;-------------------------------------------------------------- |
fs_HdWrite.access_denied: |
push ERROR_ACCESS_DENIED |
fs_HdWrite.ret0: |
pop eax |
xor ebx, ebx |
ret |
fs_HdWrite.ret11: |
push 11 |
jmp fs_HdWrite.ret0 |
fs_HdWrite: |
cmp [fs_type], 1 |
jz ntfs_HdWrite |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
push ERROR_UNKNOWN_FS |
jmp .ret0 |
@@: |
cmp byte [esi], 0 |
jz .access_denied |
pushad |
call hd_find_lfn |
pushfd |
cmp [hd_error], 0 |
jz @f |
popfd |
popad |
push 11 |
jmp .ret0 |
@@: |
popfd |
jnc .found |
popad |
push ERROR_FILE_NOT_FOUND |
jmp .ret0 |
.found: |
; FAT does not support files larger than 4GB |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
.eof: |
popad |
push ERROR_END_OF_FILE |
jmp .ret0 |
@@: |
mov ebx, [ebx] |
.l1: |
; now edi points to direntry, ebx=start byte to write, |
; ecx=number of bytes to write, edx=data pointer |
; extend file if needed |
add ecx, ebx |
jc .eof ; FAT does not support files larger than 4GB |
push eax ; save directory sector |
push 0 ; return value=0 |
call get_time_for_file |
mov [edi+22], ax ; last write time |
call get_date_for_file |
mov [edi+24], ax ; last write date |
mov [edi+18], ax ; last access date |
push dword [edi+28] ; save current file size |
cmp ecx, [edi+28] |
jbe .length_ok |
cmp ecx, ebx |
jz .length_ok |
call hd_extend_file |
jnc .length_ok |
mov [esp+4], eax |
; hd_extend_file can return three error codes: FAT table error, device error or disk full. |
; First two cases are fatal errors, in third case we may write some data |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
pop eax |
pop eax |
mov [esp+4+28], eax |
pop eax |
popad |
xor ebx, ebx |
ret |
.disk_full: |
; correct number of bytes to write |
mov ecx, [edi+28] |
cmp ecx, ebx |
ja .length_ok |
.ret: |
call update_disk |
cmp [hd_error], 0 |
jz @f |
mov byte [esp+4], 11 |
@@: |
pop eax |
pop eax |
mov [esp+4+28], eax ; eax=return value |
pop eax |
sub edx, [esp+20] |
mov [esp+16], edx ; ebx=number of written bytes |
popad |
ret |
.length_ok: |
mov esi, [edi+28] |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov edi, eax ; edi=current cluster |
xor ebp, ebp ; ebp=current sector in cluster |
; save directory |
mov eax, [esp+8] |
push ebx |
mov ebx, buffer |
call hd_write |
pop ebx |
cmp [hd_error], 0 |
jz @f |
.device_err: |
mov byte [esp+4], 11 |
jmp .ret |
@@: |
; now ebx=start pos, ecx=end pos, both lie inside file |
sub ecx, ebx |
jz .ret |
.write_loop: |
; skip unmodified sectors |
cmp dword [esp], 0x200 |
jb .modify |
sub ebx, 0x200 |
jae .skip |
add ebx, 0x200 |
.modify: |
; get length of data in current sector |
push ecx |
sub ebx, 0x200 |
jb .hasdata |
neg ebx |
xor ecx, ecx |
jmp @f |
.hasdata: |
neg ebx |
cmp ecx, ebx |
jbe @f |
mov ecx, ebx |
@@: |
; get current sector number |
mov eax, edi |
dec eax |
dec eax |
imul eax, [SECTORS_PER_CLUSTER] |
add eax, [DATA_START] |
add eax, ebp |
; load sector if needed |
cmp dword [esp+4], 0 ; we don't need to read uninitialized data |
jz .noread |
cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten |
jz .noread |
cmp ecx, esi ; (same for the last sector) |
jz .noread |
push ebx |
mov ebx, buffer |
call hd_read |
pop ebx |
cmp [hd_error], 0 |
jz @f |
.device_err2: |
pop ecx |
jmp .device_err |
@@: |
.noread: |
; zero uninitialized data if file was extended (because hd_extend_file does not this) |
push eax ecx edi |
xor eax, eax |
mov ecx, 0x200 |
sub ecx, [esp+4+12] |
jbe @f |
mov edi, buffer |
add edi, [esp+4+12] |
rep stosb |
@@: |
; zero uninitialized data in the last sector |
mov ecx, 0x200 |
sub ecx, esi |
jbe @f |
mov edi, buffer |
add edi, esi |
rep stosb |
@@: |
pop edi ecx |
; copy new data |
mov eax, edx |
neg ebx |
jecxz @f |
add ebx, buffer+0x200 |
call memmove |
xor ebx, ebx |
@@: |
pop eax |
; save sector |
push ebx |
mov ebx, buffer |
call hd_write |
pop ebx |
cmp [hd_error], 0 |
jnz .device_err2 |
add edx, ecx |
sub [esp], ecx |
pop ecx |
jz .ret |
.skip: |
; next sector |
inc ebp |
cmp ebp, [SECTORS_PER_CLUSTER] |
jb @f |
xor ebp, ebp |
mov eax, edi |
call get_FAT |
mov edi, eax |
cmp [hd_error], 0 |
jnz .device_err |
@@: |
sub esi, 0x200 |
jae @f |
xor esi, esi |
@@: |
sub dword [esp], 0x200 |
jae @f |
and dword [esp], 0 |
@@: jmp .write_loop |
hd_extend_file.zero_size: |
xor eax, eax |
jmp hd_extend_file.start_extend |
; extends file on hd to given size (new data area is undefined) |
; in: edi->direntry, ecx=new size |
; out: CF=0 => OK, eax=0 |
; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL or 11) |
hd_extend_file: |
push ebp |
mov ebp, [SECTORS_PER_CLUSTER] |
imul ebp, [BYTES_PER_SECTOR] |
push ecx |
; find the last cluster of file |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov ecx, [edi+28] |
jecxz .zero_size |
.last_loop: |
sub ecx, ebp |
jbe .last_found |
call get_FAT |
cmp [hd_error], 0 |
jz @f |
.device_err: |
pop ecx |
.device_err2: |
pop ebp |
push 11 |
.ret_err: |
pop eax |
stc |
ret |
@@: |
cmp eax, 2 |
jb .fat_err |
cmp eax, [fatRESERVED] |
jb .last_loop |
.fat_err: |
pop ecx ebp |
push ERROR_FAT_TABLE |
jmp .ret_err |
.last_found: |
push eax |
call get_FAT |
cmp [hd_error], 0 |
jz @f |
pop eax |
jmp .device_err |
@@: |
cmp eax, [fatRESERVED] |
pop eax |
jb .fat_err |
; set length to full number of clusters |
sub [edi+28], ecx |
.start_extend: |
pop ecx |
; now do extend |
push edx |
mov edx, 2 ; start scan from cluster 2 |
.extend_loop: |
cmp [edi+28], ecx |
jae .extend_done |
; add new cluster |
push eax |
mov eax, edx |
call get_free_FAT |
jc .disk_full |
mov edx, [fatEND] |
call set_FAT |
mov edx, eax |
pop eax |
test eax, eax |
jz .first_cluster |
push edx |
call set_FAT |
pop edx |
jmp @f |
.first_cluster: |
ror edx, 16 |
mov [edi+20], dx |
ror edx, 16 |
mov [edi+26], dx |
@@: |
push ecx |
mov ecx, -1 |
call add_disk_free_space |
pop ecx |
mov eax, edx |
cmp [hd_error], 0 |
jnz .device_err3 |
add [edi+28], ebp |
jmp .extend_loop |
.extend_done: |
mov [edi+28], ecx |
pop edx ebp |
xor eax, eax ; CF=0 |
ret |
.device_err3: |
pop edx |
jmp .device_err2 |
.disk_full: |
pop eax edx ebp |
push ERROR_DISK_FULL |
pop eax |
cmp [hd_error], 0 |
jz @f |
mov al, 11 |
@@: stc |
ret |
;---------------------------------------------------------------- |
; |
; fs_HdSetFileEnd - set end of file on 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 |
; |
;-------------------------------------------------------------- |
fs_HdSetFileEnd: |
cmp [fs_type], 1 |
jz ntfs_HdSetFileEnd |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
push ERROR_UNKNOWN_FS |
.ret: |
pop eax |
ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
.access_denied: |
push ERROR_ACCESS_DENIED |
jmp .ret |
@@: |
push edi |
call hd_find_lfn |
pushfd |
cmp [hd_error], 0 |
jz @f |
popfd |
push 11 |
jmp .ret |
@@: |
popfd |
jnc @f |
pop edi |
push ERROR_FILE_NOT_FOUND |
jmp .ret |
@@: |
; must not be directory |
test byte [edi+11], 10h |
jz @f |
pop edi |
jmp .access_denied |
@@: |
; file size must not exceed 4 Gb |
cmp dword [ebx+4], 0 |
jz @f |
pop edi |
push ERROR_END_OF_FILE |
jmp .ret |
@@: |
push eax ; save directory sector |
; set file modification date/time to current |
call fat_update_datetime |
mov eax, [ebx] |
cmp eax, [edi+28] |
jb .truncate |
ja .expand |
pop eax |
mov ebx, buffer |
call hd_write |
pop edi |
xor eax, eax |
cmp [hd_error], 0 |
jz @f |
mov al, 11 |
@@: |
ret |
.expand: |
push ebx ebp ecx |
push dword [edi+28] ; save old size |
mov ecx, eax |
call hd_extend_file |
push eax ; return code |
jnc .expand_ok |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
.pop_ret: |
call update_disk |
pop eax ecx ebp ebx ecx edi edi |
ret |
.expand_ok: |
.disk_full: |
; save directory |
mov eax, [edi+28] |
xchg eax, [esp+20] |
mov ebx, buffer |
call hd_write |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov edi, eax |
cmp [hd_error], 0 |
jz @f |
.pop_ret11: |
mov byte [esp], 11 |
jmp .pop_ret |
@@: |
; now zero new data |
xor ebp, ebp |
; edi=current cluster, ebp=sector in cluster |
; [esp+20]=new size, [esp+4]=old size, [esp]=return code |
.zero_loop: |
sub dword [esp+4], 0x200 |
jae .next_cluster |
lea eax, [edi-2] |
imul eax, [SECTORS_PER_CLUSTER] |
add eax, [DATA_START] |
add eax, ebp |
cmp dword [esp+4], -0x200 |
jz .noread |
mov ebx, buffer |
call hd_read |
cmp [hd_error], 0 |
jnz .err_next |
.noread: |
mov ecx, [esp+4] |
neg ecx |
push edi |
mov edi, buffer+0x200 |
add edi, [esp+8] |
push eax |
xor eax, eax |
mov [esp+12], eax |
rep stosb |
pop eax |
pop edi |
call hd_write |
cmp [hd_error], 0 |
jz .next_cluster |
.err_next: |
mov byte [esp], 11 |
.next_cluster: |
sub dword [esp+20], 0x200 |
jbe .pop_ret |
inc ebp |
cmp ebp, [SECTORS_PER_CLUSTER] |
jb .zero_loop |
xor ebp, ebp |
mov eax, edi |
call get_FAT |
mov edi, eax |
cmp [hd_error], 0 |
jnz .pop_ret11 |
jmp .zero_loop |
.truncate: |
mov [edi+28], eax |
push ecx |
mov ecx, [edi+20-2] |
mov cx, [edi+26] |
push eax |
test eax, eax |
jz .zero_size |
; find new last cluster |
@@: |
mov eax, [SECTORS_PER_CLUSTER] |
shl eax, 9 |
sub [esp], eax |
jbe @f |
mov eax, ecx |
call get_FAT |
mov ecx, eax |
cmp [hd_error], 0 |
jz @b |
.device_err3: |
pop eax ecx eax edi |
push 11 |
pop eax |
ret |
@@: |
; we will zero data at the end of last sector - remember it |
push ecx |
; terminate FAT chain |
push edx |
mov eax, ecx |
mov edx, [fatEND] |
call set_FAT |
mov eax, edx |
pop edx |
cmp [hd_error], 0 |
jz @f |
.device_err4: |
pop ecx |
jmp .device_err3 |
.zero_size: |
and word [edi+20], 0 |
and word [edi+26], 0 |
push 0 |
mov eax, ecx |
@@: |
; delete FAT chain |
call clear_cluster_chain |
cmp [hd_error], 0 |
jnz .device_err4 |
; save directory |
mov eax, [esp+12] |
push ebx |
mov ebx, buffer |
call hd_write |
pop ebx |
cmp [hd_error], 0 |
jnz .device_err4 |
; zero last sector, ignore errors |
pop ecx |
pop eax |
dec ecx |
imul ecx, [SECTORS_PER_CLUSTER] |
add ecx, [DATA_START] |
push eax |
sar eax, 9 |
add ecx, eax |
pop eax |
and eax, 0x1FF |
jz .truncate_done |
push ebx eax |
mov eax, ecx |
mov ebx, buffer |
call hd_read |
pop eax |
lea edi, [buffer+eax] |
push ecx |
mov ecx, 0x200 |
sub ecx, eax |
xor eax, eax |
rep stosb |
pop eax |
call hd_write |
pop ebx |
.truncate_done: |
pop ecx eax edi |
call update_disk |
xor eax, eax |
cmp [hd_error], 0 |
jz @f |
mov al, 11 |
@@: |
ret |
fs_HdGetFileInfo: |
cmp [fs_type], 1 |
jz ntfs_HdGetFileInfo |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
mov eax, ERROR_UNKNOWN_FS |
ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call hd_find_lfn |
pushfd |
cmp [hd_error], 0 |
jz @f |
popfd |
pop edi |
mov eax, 11 |
ret |
@@: |
popfd |
jmp fs_GetFileInfo_finish |
fs_HdSetFileInfo: |
cmp [fs_type], 1 |
jz ntfs_HdSetFileInfo |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
mov eax, ERROR_UNKNOWN_FS |
ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call hd_find_lfn |
pushfd |
cmp [hd_error], 0 |
jz @f |
popfd |
pop edi |
mov eax, 11 |
ret |
@@: |
popfd |
jnc @f |
pop edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
push eax |
call bdfe_to_fat_entry |
pop eax |
mov ebx, buffer |
call hd_write |
call update_disk |
pop edi |
xor eax, eax |
ret |
if 0 ; starting from revision 237 execute is implemented in taskman.inc |
; through fs_XxxGetFileInfo and fs_XxxRead |
;---------------------------------------------------------------- |
; |
; fs_HdExecute - LFN variant for executing from harddisk |
; |
; esi points to hd filename (e.g. 'dir1/name') |
; ebp points to full filename (e.g. '/hd0/1/dir1/name') |
; dword [ebx] = flags |
; dword [ebx+4] = cmdline |
; |
; ret ebx,edx destroyed |
; eax > 0 - PID, < 0 - error |
; |
;-------------------------------------------------------------- |
fs_HdExecute: |
mov edx, [ebx] |
mov ebx, [ebx+4] |
test ebx, ebx |
jz @f |
add ebx, std_application_base_address |
@@: |
;---------------------------------------------------------------- |
; |
; fs_HdExecute.flags - second entry |
; |
; esi points to floppy filename (kernel address) |
; ebp points to full filename |
; edx flags |
; ebx cmdline (kernel address) |
; |
; ret eax > 0 - PID, < 0 - error |
; |
;-------------------------------------------------------------- |
.flags: |
cmp [fat_type], 0 |
jnz @f |
mov eax, -ERROR_UNKNOWN_FS |
ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
; cannot execute root! |
mov eax, -ERROR_ACCESS_DENIED |
ret |
@@: |
push edi |
call hd_find_lfn |
jnc .found |
pop edi |
mov eax, -ERROR_FILE_NOT_FOUND |
cmp [hd_error], 0 |
jz @f |
mov al, -11 |
@@: |
ret |
.found: |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
push 0 |
push eax |
push dword [edi+28] ; size |
push .DoRead |
call fs_execute |
add esp, 16 |
pop edi |
ret |
.DoRead: |
; read next block |
; in: eax->parameters, edi->buffer |
; out: eax = error code |
pushad |
cmp dword [eax], 0 ; file size |
jz .eof |
add eax, 4 |
call fat_get_sector |
mov ebx, edi |
call hd_read |
cmp [hd_error], 0 |
jnz .err |
mov eax, [esp+28] |
mov ecx, [eax] |
sub ecx, 512 |
jae @f |
lea edi, [edi+ecx+512] |
neg ecx |
push eax |
xor eax, eax |
rep stosb |
pop eax |
@@: |
mov [eax], ecx |
mov edx, [eax+8] |
inc edx |
cmp edx, [SECTORS_PER_CLUSTER] |
jb @f |
push eax |
mov eax, [eax+4] |
call get_FAT |
cmp [hd_error], 0 |
jnz .err |
mov ecx, eax |
pop eax |
mov [eax+4], ecx |
xor edx, edx |
@@: |
mov [eax+8], edx |
popad |
xor eax, eax |
ret |
.eof: |
popad |
mov eax, 6 |
ret |
.err: |
popad |
mov eax, 11 |
ret |
end if |
;---------------------------------------------------------------- |
; |
; fs_HdDelete - delete file or empty folder from hard disk |
; |
; esi points to filename |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_HdDelete: |
cmp [fs_type], 1 |
jz ntfs_HdDelete |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
push ERROR_UNKNOWN_FS |
.pop_ret: |
pop eax |
ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
; cannot delete root! |
.access_denied: |
push ERROR_ACCESS_DENIED |
jmp .pop_ret |
@@: |
and [longname_sec1], 0 |
and [longname_sec2], 0 |
push edi |
call hd_find_lfn |
jnc .found |
pop edi |
push ERROR_FILE_NOT_FOUND |
jmp .pop_ret |
.found: |
cmp dword [edi], '. ' |
jz .access_denied2 |
cmp dword [edi], '.. ' |
jz .access_denied2 |
test byte [edi+11], 10h |
jz .dodel |
; we can delete only empty folders! |
pushad |
mov ebp, [edi+20-2] |
mov bp, [edi+26] |
xor ecx, ecx |
lea eax, [ebp-2] |
imul eax, [SECTORS_PER_CLUSTER] |
add eax, [DATA_START] |
mov ebx, buffer |
call hd_read |
cmp [hd_error], 0 |
jnz .err1 |
add ebx, 2*0x20 |
.checkempty: |
cmp byte [ebx], 0 |
jz .empty |
cmp byte [ebx], 0xE5 |
jnz .notempty |
add ebx, 0x20 |
cmp ebx, buffer+0x200 |
jb .checkempty |
inc ecx |
cmp ecx, [SECTORS_PER_CLUSTER] |
jb @f |
mov eax, ebp |
call get_FAT |
cmp [hd_error], 0 |
jnz .err1 |
mov ebp, eax |
xor ecx, ecx |
@@: |
lea eax, [ebp-2] |
imul eax, [SECTORS_PER_CLUSTER] |
add eax, [DATA_START] |
add eax, ecx |
mov ebx, buffer |
call hd_read |
cmp [hd_error], 0 |
jz .checkempty |
.err1: |
popad |
.err2: |
pop edi |
push 11 |
pop eax |
ret |
.notempty: |
popad |
.access_denied2: |
pop edi |
push ERROR_ACCESS_DENIED |
pop eax |
ret |
.empty: |
popad |
push ebx |
mov ebx, buffer |
call hd_read |
pop ebx |
cmp [hd_error], 0 |
jnz .err2 |
.dodel: |
push eax |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
xchg eax, [esp] |
; delete folder entry |
mov byte [edi], 0xE5 |
; delete LFN (if present) |
.lfndel: |
cmp edi, buffer |
ja @f |
cmp [longname_sec2], 0 |
jz .lfndone |
push [longname_sec2] |
push [longname_sec1] |
pop [longname_sec2] |
and [longname_sec1], 0 |
push ebx |
mov ebx, buffer |
call hd_write |
mov eax, [esp+4] |
call hd_read |
pop ebx |
pop eax |
mov edi, buffer+0x200 |
@@: |
sub edi, 0x20 |
cmp byte [edi], 0xE5 |
jz .lfndone |
cmp byte [edi+11], 0xF |
jnz .lfndone |
mov byte [edi], 0xE5 |
jmp .lfndel |
.lfndone: |
push ebx |
mov ebx, buffer |
call hd_write |
pop ebx |
; delete FAT chain |
pop eax |
call clear_cluster_chain |
call update_disk |
pop edi |
xor eax, eax |
cmp [hd_error], 0 |
jz @f |
mov al, 11 |
@@: |
ret |
; \end{diamond} |
/kernel/tags/kolibri0.6.5.0/fs/fs.inc |
---|
0,0 → 1,835 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; System service for filesystem call ;; |
;; (C) 2004 Ville Turjanmaa, License: GPL ;; |
;; 29.04.2006 Elimination of hangup after the ;; |
;; expiration hd_wait_timeout (for LBA) - Mario79 ;; |
;; 15.01.2005 get file size/attr/date, file_append (only for hd) - ATV ;; |
;; 23.11.2004 test if hd/partition is set - ATV ;; |
;; 18.11.2004 get_disk_info and more error codes - ATV ;; |
;; 08.11.2004 expand_pathz and rename (only for hd) - ATV ;; |
;; 20.10.2004 Makedir/Removedir (only for hd) - ATV ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
iglobal |
dir0: db 'HARDDISK ' |
db 'RAMDISK ' |
db 'FLOPPYDISK ' |
db 0 |
dir1: db 'FIRST ' |
db 'SECOND ' |
db 'THIRD ' |
db 'FOURTH ' |
db 0 |
not_select_IDE db 0 |
hd_address_table: dd 0x1f0,0x00,0x1f0,0x10 |
dd 0x170,0x00,0x170,0x10 |
endg |
file_system: |
; IN: |
; |
; eax = 0 ; read file /RamDisk/First 6 |
; eax = 1 ; write file /RamDisk/First 33 /HardDisk/First 56 |
; eax = 8 ; lba read |
; eax = 15 ; get_disk_info |
; |
; OUT: |
; |
; eax = 0 : read ok |
; eax = 1 : no hd base and/or partition defined |
; eax = 2 : function is unsupported for this FS |
; eax = 3 : unknown FS |
; eax = 4 : partition not defined at hd |
; eax = 5 : file not found |
; eax = 6 : end of file |
; eax = 7 : memory pointer not in application area |
; eax = 8 : disk full |
; eax = 9 : fat table corrupted |
; eax = 10 : access denied |
; eax = 11 : disk error |
; |
; ebx = size |
; \begin{diamond}[18.03.2006] |
; for subfunction 16 (start application) error codes must be negative |
; because positive values are valid PIDs |
; so possible return values are: |
; eax > 0 : process created, eax=PID |
; -0x10 <= eax < 0 : -eax is filesystem error code: |
; eax = -1 = 0xFFFFFFFF : no hd base and/or partition defined |
; eax = -3 = 0xFFFFFFFD : unknown FS |
; eax = -5 = 0xFFFFFFFB : file not found |
; eax = -6 = 0xFFFFFFFA : unexpected end of file (probably not executable file) |
; eax = -9 = 0xFFFFFFF7 : fat table corrupted |
; eax = -10 = 0xFFFFFFF6 : access denied |
; -0x20 <= eax < -0x10: eax is process creation error code: |
; eax = -0x20 = 0xFFFFFFE0 : too many processes |
; eax = -0x1F = 0xFFFFFFE1 : not Menuet/Kolibri executable |
; eax = -0x1E = 0xFFFFFFE2 : no memory |
; ebx is not changed |
; \end{diamond}[18.03.2006] |
; Extract parameters |
add eax, std_application_base_address ; abs start of info block |
cmp dword [eax+0],15 ; GET_DISK_INFO |
je fs_info |
cmp dword [0x3000],1 ; no memory checks for kernel requests |
jz no_checks_for_kernel |
mov edx,eax |
cmp dword [eax+0],1 |
jnz .usual_check |
mov ebx,[eax+12] |
add ebx,std_application_base_address |
mov ecx,[eax+8] |
call check_region |
test eax,eax |
jnz area_in_app_mem |
.error_output: |
mov esi,buffer_failed |
call sys_msg_board_str |
; mov eax,7 |
mov dword [esp+36],7 |
ret |
iglobal |
buffer_failed db 'K : Buffer check failed',13,10,0 |
endg |
.usual_check: |
cmp dword [eax+0],0 |
mov ecx,512 |
jnz .small_size |
mov ecx,[eax+8] |
shl ecx,9 |
.small_size: |
mov ebx,[eax+12] |
add ebx,std_application_base_address |
call check_region |
test eax,eax |
jz .error_output |
area_in_app_mem: |
mov eax,edx |
no_checks_for_kernel: |
fs_read: |
mov ebx,[eax+20] ; program wants root directory ? |
test bl,bl |
je fs_getroot |
test bh,bh |
jne fs_noroot |
fs_getroot: |
; \begin{diamond}[18.03.2006] |
; root - only read is allowed |
; other operations return "access denied", eax=10 |
; (execute operation returns eax=-10) |
cmp dword [eax], 0 |
jz .read_root |
mov dword [esp+36], 10 |
ret |
.read_root: |
; \end{diamond}[18.03.2006] |
mov esi,dir0 |
mov edi,[eax+12] |
add edi,std_application_base_address |
mov ecx,11 |
push ecx |
; cld ; already is |
rep movsb |
mov al,0x10 |
stosb |
add edi,32-11-1 |
pop ecx |
rep movsb |
stosb |
and dword [esp+36],0 ; ok read |
mov dword [esp+24],32*2 ; size of root |
ret |
fs_info: ;start of code - Mihasik |
push eax |
cmp [eax+21],byte 'h' |
je fs_info_h |
cmp [eax+21],byte 'H' |
je fs_info_h |
cmp [eax+21],byte 'r' |
je fs_info_r |
cmp [eax+21],byte 'R' |
je fs_info_r |
mov eax,3 ;if unknown disk |
xor ebx,ebx |
xor ecx,ecx |
xor edx,edx |
jmp fs_info1 |
fs_info_r: |
call ramdisk_free_space ;if ramdisk |
mov ecx,edi ;free space in ecx |
shr ecx,9 ;free clusters |
mov ebx,2847 ;total clusters |
mov edx,512 ;cluster size |
xor eax,eax ;always 0 |
jmp fs_info1 |
fs_info_h: ;if harddisk |
call get_hd_info |
fs_info1: |
pop edi |
mov [esp+36],eax |
mov [esp+24],ebx ; total clusters on disk |
mov [esp+32],ecx ; free clusters on disk |
mov [edi],edx ; cluster size in bytes |
ret ;end of code - Mihasik |
fs_noroot: |
push dword [eax+0] ; read/write/delete/.../makedir/rename/lba/run |
push dword [eax+4] ; 512 block number to read |
push dword [eax+8] ; bytes to write/append or 512 blocks to read |
mov ebx,[eax+12] |
add ebx,std_application_base_address |
push ebx ; abs start of return/save area |
lea esi,[eax+20] ; abs start of dir + filename |
mov edi,[eax+16] |
add edi,std_application_base_address ; abs start of work area |
call expand_pathz |
push edi ; dir start |
push ebx ; name of file start |
mov eax,[edi+1] |
cmp eax,'RD ' |
je fs_yesramdisk |
cmp eax,'RAMD' |
jne fs_noramdisk |
fs_yesramdisk: |
cmp byte [edi+1+11],0 |
je fs_give_dir1 |
mov eax,[edi+1+12] |
cmp eax,'1 ' |
je fs_yesramdisk_first |
cmp eax,'FIRS' |
jne fs_noramdisk |
fs_yesramdisk_first: |
cmp dword [esp+20],8 ; LBA read ramdisk |
jne fs_no_LBA_read_ramdisk |
mov eax,[esp+16] ; LBA block to read |
mov ecx,[esp+8] ; abs pointer to return area |
call LBA_read_ramdisk |
jmp file_system_return |
fs_no_LBA_read_ramdisk: |
cmp dword [esp+20],0 ; READ |
jne fs_noramdisk_read |
mov eax,[esp+4] ; fname |
add eax,2*12+1 |
mov ebx,[esp+16] ; block start |
inc ebx |
mov ecx,[esp+12] ; block count |
mov edx,[esp+8] ; return |
mov esi,[esp+0] |
sub esi,eax |
add esi,12+1 ; file name length |
call fileread |
jmp file_system_return |
fs_noramdisk_read: |
cmp dword [esp+20],1 ; WRITE |
jne fs_noramdisk_write |
mov eax,[esp+4] ; fname |
add eax,2*12+1 |
mov ebx,[esp+8] ; buffer |
mov ecx,[esp+12] ; count to write |
mov edx,0 ; create new |
call filesave |
; eax=0 ok - eax=1 not enough free space |
jmp file_system_return |
fs_noramdisk_write: |
fs_noramdisk: |
;******************************************************************** |
mov eax,[edi+1] |
cmp eax,'FD ' |
je fs_yesflpdisk |
cmp eax,'FLOP' |
jne fs_noflpdisk |
fs_yesflpdisk: |
call reserve_flp |
cmp byte [edi+1+11],0 |
je fs_give_dir1 |
mov eax,[edi+1+12] |
cmp eax,'1 ' |
je fs_yesflpdisk_first |
cmp eax,'FIRS' |
je fs_yesflpdisk_first |
cmp eax,'2 ' |
je fs_yesflpdisk_second |
cmp eax,'SECO' |
jne fs_noflpdisk |
jmp fs_yesflpdisk_second |
fs_yesflpdisk_first: |
mov [flp_number],1 |
jmp fs_yesflpdisk_start |
fs_yesflpdisk_second: |
mov [flp_number],2 |
fs_yesflpdisk_start: |
cmp dword [esp+20],0 ; READ |
jne fs_noflpdisk_read |
mov eax,[esp+4] ; fname |
add eax,2*12+1 |
mov ebx,[esp+16] ; block start |
inc ebx |
mov ecx,[esp+12] ; block count |
mov edx,[esp+8] ; return |
mov esi,[esp+0] |
sub esi,eax |
add esi,12+1 ; file name length |
call floppy_fileread |
jmp file_system_return |
fs_noflpdisk_read: |
cmp dword [esp+20],1 ; WRITE |
jne fs_noflpdisk_write |
mov eax,[esp+4] ; fname |
add eax,2*12+1 |
mov ebx,[esp+8] ; buffer |
mov ecx,[esp+12] ; count to write |
mov edx,0 ; create new |
call floppy_filesave |
; eax=0 ok - eax=1 not enough free space |
jmp file_system_return |
fs_noflpdisk_write: |
fs_noflpdisk: |
;***************************************************************** |
mov eax,[edi+1] |
cmp eax,'HD0 ' |
je fs_yesharddisk_IDE0 |
cmp eax,'HD1 ' |
je fs_yesharddisk_IDE1 |
cmp eax,'HD2 ' |
je fs_yesharddisk_IDE2 |
cmp eax,'HD3 ' |
je fs_yesharddisk_IDE3 |
jmp old_path_harddisk |
fs_yesharddisk_IDE0: |
call reserve_hd1 |
mov [hdbase],0x1f0 |
mov [hdid],0x0 |
mov [hdpos],1 |
jmp fs_yesharddisk_partition |
fs_yesharddisk_IDE1: |
call reserve_hd1 |
mov [hdbase],0x1f0 |
mov [hdid],0x10 |
mov [hdpos],2 |
jmp fs_yesharddisk_partition |
fs_yesharddisk_IDE2: |
call reserve_hd1 |
mov [hdbase],0x170 |
mov [hdid],0x0 |
mov [hdpos],3 |
jmp fs_yesharddisk_partition |
fs_yesharddisk_IDE3: |
call reserve_hd1 |
mov [hdbase],0x170 |
mov [hdid],0x10 |
mov [hdpos],4 |
fs_yesharddisk_partition: |
call reserve_hd_channel |
; call choice_necessity_partition |
; jmp fs_yesharddisk_all |
jmp fs_for_new_semantic |
choice_necessity_partition: |
mov eax,[edi+1+12] |
call StringToNumber |
mov [fat32part],eax |
choice_necessity_partition_1: |
mov ecx,[hdpos] |
xor eax,eax |
mov [0xfe10], eax ; entries in hd cache |
mov edx,0x40002 |
search_partition_array: |
mov bl,[edx] |
movzx ebx,bl |
add eax,ebx |
inc edx |
loop search_partition_array |
sub eax,ebx |
add eax,[fat32part] |
dec eax |
xor edx,edx |
imul eax,100 |
add eax,0x4000a |
mov [transfer_adress],eax |
call partition_data_transfer_1 |
ret |
old_path_harddisk: |
mov eax,[edi+1] |
cmp eax,'HD ' |
je fs_yesharddisk |
cmp eax,'HARD' |
jne fs_noharddisk |
fs_yesharddisk: |
cmp dword [esp+20],8 ; LBA read |
jne fs_no_LBA_read |
mov eax,[esp+16] ; LBA block to read |
lea ebx,[edi+1+12] ; pointer to FIRST/SECOND/THIRD/FOURTH |
mov ecx,[esp+8] ; abs pointer to return area |
call LBA_read |
jmp file_system_return |
fs_no_LBA_read: |
cmp byte [edi+1+11],0 ; directory read |
je fs_give_dir1 |
call reserve_hd1 |
fs_for_new_semantic: |
call choice_necessity_partition |
fs_yesharddisk_all: |
mov eax,1 |
mov ebx, [esp+24+24] |
cmp [hdpos],0 ; is hd base set? |
jz hd_err_return |
cmp [fat32part],0 ; is partition set? |
jnz @f |
hd_err_return: |
call free_hd_channel |
and [hd1_status], 0 |
jmp file_system_return |
@@: |
cmp dword [esp+20],0 ; READ |
jne fs_noharddisk_read |
mov eax,[esp+0] ; /fname |
lea edi,[eax+12] |
mov byte [eax],0 ; path to asciiz |
inc eax ; filename start |
mov ebx,[esp+12] ; count to read |
mov ecx,[esp+8] ; buffer |
mov edx,[esp+4] |
add edx,12*2 ; dir start |
sub edi,edx ; path length |
mov esi,[esp+16] ; blocks to read |
call file_read |
mov edi,[esp+0] |
mov byte [edi],'/' |
call free_hd_channel |
and [hd1_status], 0 |
jmp file_system_return |
fs_noharddisk_read: |
cmp dword [esp+20],1 ; WRITE |
jne fs_noharddisk_write |
mov eax,[esp+0] ; /fname |
mov byte [eax],0 ; path to asciiz |
inc eax ; filename start |
mov ebx,[esp+12] ; count to write |
mov ecx,[esp+8] ; buffer |
mov edx,[esp+4] |
add edx,12*2 ; path start |
call file_write |
mov edi,[esp+0] |
mov byte [edi],'/' |
; eax=0 ok - eax=1 not enough free space |
call free_hd_channel |
and [hd1_status], 0 |
jmp file_system_return |
fs_noharddisk_write: |
call free_hd_channel |
and [hd1_status], 0 |
fs_noharddisk: |
; \begin{diamond}[18.03.2006] |
mov eax, 5 ; file not found |
; à ìîæåò áûòü, âîçâðàùàòü äðóãîé êîä îøèáêè? |
mov ebx, [esp+24+24] ; do not change ebx in application |
; \end{diamond}[18.03.2006] |
file_system_return: |
add esp,24 |
mov [esp+36],eax |
mov [esp+24],ebx |
ret |
fs_give_dir1: |
; \begin{diamond}[18.03.2006] |
; /RD,/FD,/HD - only read is allowed |
; other operations return "access denied", eax=10 |
; (execute operation returns eax=-10) |
cmp dword [esp+20], 0 |
jz .read |
add esp, 20 |
pop ecx |
mov dword [esp+36], 10 |
ret |
.read: |
; \end{diamond}[18.03.2006] |
mov al,0x10 |
mov ebx,1 |
mov edi,[esp+8] |
mov esi,dir1 |
fs_d1_new: |
mov ecx,11 |
; cld |
rep movsb |
stosb |
add edi,32-11-1 |
dec ebx |
jne fs_d1_new |
add esp,24 |
and dword [esp+36],0 ; ok read |
mov dword [esp+24],32*1 ; dir/data size |
ret |
LBA_read_ramdisk: |
cmp [lba_read_enabled],1 |
je lbarrl1 |
xor ebx,ebx |
mov eax,2 |
ret |
lbarrl1: |
cmp eax,18*2*80 |
jb lbarrl2 |
xor ebx,ebx |
mov eax,3 |
ret |
lbarrl2: |
pushad |
call restorefatchain |
mov edi,ecx |
mov esi,eax |
shl esi,9 |
add esi,0x100000 |
mov ecx,512/4 |
; cld |
rep movsd |
popad |
xor ebx,ebx |
xor eax,eax |
ret |
LBA_read: |
; IN: |
; |
; eax = LBA block to read |
; ebx = pointer to FIRST/SECOND/THIRD/FOURTH |
; ecx = abs pointer to return area |
cmp [lba_read_enabled],1 |
je lbarl1 |
mov eax,2 |
ret |
lbarl1: |
call reserve_hd1 |
push eax |
push ecx |
mov edi,hd_address_table |
mov esi,dir1 |
mov eax,[ebx] |
mov edx,'1 ' |
mov ecx,4 |
blar0: |
cmp eax,[esi] |
je blar2 |
cmp eax,edx |
je blar2 |
inc edx |
add edi,8 |
add esi,11 |
dec ecx |
jnz blar0 |
mov eax,1 |
mov ebx,1 |
jmp LBA_read_ret |
blar2: |
mov eax,[edi+0] |
mov ebx,[edi+4] |
mov [hdbase],eax |
mov [hdid],ebx |
call wait_for_hd_idle |
cmp [hd_error],0 |
jne hd_lba_error |
; eax = hd port |
; ebx = set for primary (0x00) or slave (0x10) |
cli |
mov edx,eax |
inc edx |
xor eax,eax |
out dx,al |
inc edx |
inc eax |
out dx,al |
inc edx |
mov eax,[esp+4] |
out dx,al |
shr eax,8 |
inc edx |
out dx,al |
shr eax,8 |
inc edx |
out dx,al |
shr eax,8 |
inc edx |
and al,1+2+4+8 |
add al,bl |
add al,128+64+32 |
out dx,al |
inc edx |
mov al,20h |
out dx,al |
sti |
call wait_for_sector_buffer |
cmp [hd_error],0 |
jne hd_lba_error |
cli |
mov edi,[esp+0] |
mov ecx,256 |
sub edx,7 |
cld |
rep insw |
sti |
xor eax,eax |
xor ebx,ebx |
LBA_read_ret: |
mov [hd_error],0 |
mov [hd1_status],0 |
add esp,2*4 |
ret |
expand_pathz: |
; IN: |
; esi = asciiz path & file |
; edi = buffer for path & file name |
; OUT: |
; edi = directory & file : / 11 + / 11 + / 11 - zero terminated |
; ebx = /file name - zero terminated |
; esi = pointer after source |
push eax |
push ecx |
push edi ;[esp+0] |
pathz_start: |
mov byte [edi],'/' |
inc edi |
mov al,32 |
mov ecx,11 |
cld |
rep stosb ; clear filename area |
sub edi,11 |
mov ebx,edi ; start of dir/file name |
pathz_new_char: |
mov al,[esi] |
inc esi |
cmp al,0 |
je pathz_end |
cmp al,'/' |
jne pathz_not_path |
cmp edi,ebx ; skip first '/' |
jz pathz_new_char |
lea edi,[ebx+11] ; start of next directory |
jmp pathz_start |
pathz_not_path: |
cmp al,'.' |
jne pathz_not_ext |
lea edi,[ebx+8] ; start of extension |
jmp pathz_new_char |
pathz_not_ext: |
cmp al,'a' |
jb pathz_not_low |
cmp al,'z' |
ja pathz_not_low |
sub al,0x20 ; char to uppercase |
pathz_not_low: |
mov [edi],al |
inc edi |
mov eax,[esp+0] ; start_of_dest_path |
add eax,512 ; keep maximum path under 512 bytes |
cmp edi,eax |
jb pathz_new_char |
pathz_end: |
cmp ebx,edi ; if path end with '/' |
jnz pathz_put_zero ; go back 1 level |
sub ebx,12 |
pathz_put_zero: |
mov byte [ebx+11],0 |
dec ebx ; include '/' char into file name |
pop edi |
pop ecx |
pop eax |
ret |
;******************************************* |
;* string to number |
;* input eax - 4 byte string |
;* output eax - number |
;******************************************* |
StringToNumber: |
; ÏÅÐÅÂÎÄ ÑÒÐÎÊÎÂÎÃÎ ×ÈÑËÀ  ×ÈÑËÎÂÎÉ ÂÈÄ |
; Âõîä: |
; EDI - àäðåñ ñòðîêè ñ ÷èñëîì. Êîíåö ÷èñëà îòìå÷åí êîäîì 0Dh |
; Âûõîä: |
; CF - èíäèêàòîð îøèáîê: |
; 0 - îøèáîê íåò; |
; 1 - îøèáêà |
; Åñëè CF=0, òî AX - ÷èñëî. |
push bx |
push cx |
push dx |
push edi |
mov [partition_string],eax |
mov edi,partition_string |
xor cx,cx |
i1: |
mov al,[edi] |
cmp al,32 ;13 |
je i_exit |
; cmp al,'0' |
; jb err |
; cmp al,'9' |
; ja err |
sub al,48 |
shl cx,1 |
jc err |
mov bx,cx |
shl cx,1 |
jc err |
shl cx,1 |
jc err |
add cx,bx |
jc err |
cbw |
add cx,ax |
jc err |
i3: |
inc edi |
jmp i1 |
i_exit: |
mov ax,cx |
clc |
i4: |
movzx eax,ax |
pop edi |
pop dx |
pop cx |
pop bx |
ret |
err: |
stc |
jmp i4 |
partition_string: dd 0 |
db 32 |
/kernel/tags/kolibri0.6.5.0/fs/fs_lfn.inc |
---|
0,0 → 1,678 |
; System function 70 - files with long names (LFN) |
; diamond, 2006 |
iglobal |
; in this table names must be in lowercase |
rootdirs: |
db 2,'rd' |
dd fs_OnRamdisk |
dd fs_NextRamdisk |
db 7,'ramdisk' |
dd fs_OnRamdisk |
dd fs_NextRamdisk |
db 2,'fd' |
dd fs_OnFloppy |
dd fs_NextFloppy |
db 10,'floppydisk' |
dd fs_OnFloppy |
dd fs_NextFloppy |
db 3,'hd0' |
dd fs_OnHd0 |
dd fs_NextHd0 |
db 3,'hd1' |
dd fs_OnHd1 |
dd fs_NextHd1 |
db 3,'hd2' |
dd fs_OnHd2 |
dd fs_NextHd2 |
db 3,'hd3' |
dd fs_OnHd3 |
dd fs_NextHd3 |
;********************************************** |
db 3,'cd0' |
dd fs_OnCd0 |
dd fs_NextCd |
db 3,'cd1' |
dd fs_OnCd1 |
dd fs_NextCd |
db 3,'cd2' |
dd fs_OnCd2 |
dd fs_NextCd |
db 3,'cd3' |
dd fs_OnCd3 |
dd fs_NextCd |
;*********************************************** |
db 0 |
virtual_root_query: |
dd fs_HasRamdisk |
db 'rd',0 |
dd fs_HasFloppy |
db 'fd',0 |
dd fs_HasHd0 |
db 'hd0',0 |
dd fs_HasHd1 |
db 'hd1',0 |
dd fs_HasHd2 |
db 'hd2',0 |
dd fs_HasHd3 |
db 'hd3',0 |
;********************************************** |
dd fs_HasCd0 |
db 'cd0',0 |
dd fs_HasCd1 |
db 'cd1',0 |
dd fs_HasCd2 |
db 'cd2',0 |
dd fs_HasCd3 |
db 'cd3',0 |
;********************************************** |
dd 0 |
endg |
file_system_lfn: |
; in: eax->fileinfo block |
; operation codes: |
; 0 : read file |
; 1 : read folder |
; 2 : create/rewrite file |
; 3 : write/append to file |
; 4 : set end of file |
; 5 : get file/directory attributes structure |
; 6 : set file/directory attributes structure |
; 7 : start application |
; 8 : delete file |
; 9 : create directory |
add eax, std_application_base_address |
; parse file name |
xchg ebx, eax |
lea esi, [ebx+20] |
mov ebp, esi ; for 'start app' function full path must be known |
lodsb |
test al, al |
jnz @f |
mov esi, [esi] |
add esi, std_application_base_address |
mov ebp, esi |
lodsb |
@@: |
cmp dword [ebx], 7 |
jne @F |
mov edx, [ebx+4] |
mov ebx, [ebx+8] |
test ebx, ebx |
jz .l1 |
add ebx, new_app_base |
.l1: |
call fs_execute ; ebp, ebx, edx |
mov [esp+36], eax |
ret |
@@: |
cmp al, '/' |
jz @f |
.notfound: |
mov dword [esp+36], 5 ; file not found |
ret |
@@: |
cmp byte [esi], 0 |
jz .rootdir |
mov edi, rootdirs-8 |
xor ecx, ecx |
push esi |
.scan1: |
pop esi |
add edi, ecx |
scasd |
scasd |
mov cl, byte [edi] |
jecxz .notfound |
inc edi |
push esi |
@@: |
lodsb |
or al, 20h |
scasb |
loopz @b |
jnz .scan1 |
lodsb |
cmp al, '/' |
jz .found1 |
test al, al |
jnz .scan1 |
pop eax |
; directory /xxx |
.maindir: |
cmp dword [ebx], 1 |
jnz .access_denied |
xor eax, eax |
mov ebp, [ebx+12] |
mov edx, [ebx+16] |
add edx, std_application_base_address |
push dword [ebx+4] ; first block |
mov ebx, [ebx+8] ; flags |
mov esi, [edi+4] |
; ebx=flags, [esp]=first block, ebp=number of blocks, edx=return area, esi='Next' handler |
mov edi, edx |
mov ecx, 32/4 |
rep stosd |
mov byte [edx], 1 ; version |
.maindir_loop: |
call esi |
jc .maindir_done |
inc dword [edx+8] |
dec dword [esp] |
jns .maindir_loop |
dec ebp |
js .maindir_loop |
inc dword [edx+4] |
mov dword [edi], 0x10 ; attributes: folder |
mov dword [edi+4], 1 ; name type: UNICODE |
push eax |
xor eax, eax |
add edi, 8 |
mov ecx, 40/4-2 |
rep stosd |
pop eax |
push eax edx |
; convert number in eax to decimal UNICODE string |
push edi |
push -'0' |
mov cl, 10 |
@@: |
xor edx, edx |
div ecx |
push edx |
test eax, eax |
jnz @b |
@@: |
pop eax |
add al, '0' |
stosb |
test bl, 1 ; UNICODE name? |
jz .ansi2 |
mov byte [edi], 0 |
inc edi |
.ansi2: |
test al, al |
jnz @b |
mov byte [edi-1], 0 |
pop edi |
; UNICODE name length is 520 bytes, ANSI - 264 |
add edi, 520 |
test bl, 1 |
jnz @f |
sub edi, 520-264 |
@@: |
pop edx eax |
jmp .maindir_loop |
.maindir_done: |
pop eax |
mov ebx, [edx+4] |
xor eax, eax |
dec ebp |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
; directory / |
.rootdir: |
cmp dword [ebx], 1 ; read folder? |
jz .readroot |
.access_denied: |
mov dword [esp+36], 10 ; access denied |
ret |
.readroot: |
; virtual root folder - special handler |
mov esi, virtual_root_query |
mov ebp, [ebx+12] |
mov edx, [ebx+16] |
add edx, std_application_base_address |
push dword [ebx+4] ; first block |
mov ebx, [ebx+8] ; flags |
xor eax, eax |
; eax=0, [esp]=first block, ebx=flags, ebp=number of blocks, edx=return area |
mov edi, edx |
mov ecx, 32/4 |
rep stosd |
mov byte [edx], 1 ; version |
.readroot_loop: |
cmp dword [esi], eax |
jz .readroot_done |
call dword [esi] |
add esi, 4 |
test eax, eax |
jnz @f |
.readroot_next: |
or ecx, -1 |
xchg esi, edi |
repnz scasb |
xchg esi, edi |
jmp .readroot_loop |
@@: |
xor eax, eax |
inc dword [edx+8] |
dec dword [esp] |
jns .readroot_next |
dec ebp |
js .readroot_next |
inc dword [edx+4] |
mov dword [edi], 0x10 ; attributes: folder |
mov dword [edi+4], 1 ; name type: UNICODE |
add edi, 8 |
mov ecx, 40/4-2 |
rep stosd |
push edi |
@@: |
lodsb |
stosb |
test bl, 1 |
jz .ansi |
mov byte [edi], 0 |
inc edi |
.ansi: |
test eax, eax |
jnz @b |
pop edi |
add edi, 520 |
test bl, 1 |
jnz .readroot_loop |
sub edi, 520-264 |
jmp .readroot_loop |
.readroot_done: |
pop eax |
mov ebx, [edx+4] |
xor eax, eax |
dec ebp |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
.found1: |
pop eax |
cmp byte [esi], 0 |
jz .maindir |
; read partition number |
xor ecx, ecx |
xor eax, eax |
@@: |
lodsb |
cmp al, '/' |
jz .done1 |
test al, al |
jz .done1 |
sub al, '0' |
cmp al, 9 |
ja .notfound |
imul ecx, 10 |
add ecx, eax |
jmp @b |
.done1: |
test ecx, ecx |
jz .notfound |
test al, al |
jnz @f |
dec esi |
@@: |
; now [edi] contains handler address, ecx - partition number, |
; esi points to ASCIIZ string - rest of name |
jmp dword [edi] |
; handlers for devices |
; in: ecx = 0 => query virtual directory /xxx |
; in: ecx = partition number |
; esi -> relative (for device) name |
; ebx -> fileinfo |
; out: [esp+36]=image of eax, [esp+24]=image of ebx |
fs_OnRamdisk: |
cmp ecx, 1 |
jnz file_system_lfn.notfound |
mov eax, [ebx] |
cmp eax, fs_NumRamdiskServices |
jae .not_impl |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
add edx, std_application_base_address |
add ebx, 4 |
call dword [fs_RamdiskServices + eax*4] |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
.not_impl: |
mov dword [esp+36], 2 ; not implemented |
ret |
fs_NotImplemented: |
mov eax, 2 |
ret |
fs_RamdiskServices: |
dd fs_RamdiskRead |
dd fs_RamdiskReadFolder |
dd fs_RamdiskRewrite |
dd fs_RamdiskWrite |
dd fs_RamdiskSetFileEnd |
dd fs_RamdiskGetFileInfo |
dd fs_RamdiskSetFileInfo |
dd 0 ;fs_RamdiskExecute |
dd fs_RamdiskDelete |
dd fs_RamdiskCreateFolder |
fs_NumRamdiskServices = ($ - fs_RamdiskServices)/4 |
fs_OnFloppy: |
cmp ecx, 2 |
ja file_system_lfn.notfound |
mov eax, [ebx] |
cmp eax, fs_NumFloppyServices |
jae fs_OnRamdisk.not_impl |
call reserve_flp |
mov [flp_number], cl |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
add edx, std_application_base_address |
add ebx, 4 |
call dword [fs_FloppyServices + eax*4] |
and [flp_status], 0 |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
fs_FloppyServices: |
dd fs_FloppyRead |
dd fs_FloppyReadFolder |
dd fs_FloppyRewrite |
dd fs_FloppyWrite |
dd fs_FloppySetFileEnd |
dd fs_FloppyGetFileInfo |
dd fs_FloppySetFileInfo |
dd 0 ;fs_FloppyExecute |
dd fs_FloppyDelete |
dd fs_FloppyCreateFolder |
fs_NumFloppyServices = ($ - fs_FloppyServices)/4 |
fs_OnHd0: |
call reserve_hd1 |
mov [hdbase], 0x1F0 |
mov [hdid], 0 |
push 1 |
jmp fs_OnHd |
fs_OnHd1: |
call reserve_hd1 |
mov [hdbase], 0x1F0 |
mov [hdid], 0x10 |
push 2 |
jmp fs_OnHd |
fs_OnHd2: |
call reserve_hd1 |
mov [hdbase], 0x170 |
mov [hdid], 0 |
push 3 |
jmp fs_OnHd |
fs_OnHd3: |
call reserve_hd1 |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
push 4 |
fs_OnHd: |
call reserve_hd_channel |
pop eax |
mov [hdpos], eax |
cmp ecx, 0x100 |
jae .nf |
cmp cl, [0x40001+eax] |
jbe @f |
.nf: |
call free_hd_channel |
and [hd1_status], 0 |
mov dword [esp+36], 5 ; not found |
ret |
@@: |
mov [fat32part], ecx |
push ebx esi |
call choice_necessity_partition_1 |
pop esi ebx |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
add edx, std_application_base_address |
mov eax, [ebx] |
cmp eax, fs_NumHdServices |
jae .not_impl |
add ebx, 4 |
call dword [fs_HdServices + eax*4] |
call free_hd_channel |
and [hd1_status], 0 |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
.not_impl: |
call free_hd_channel |
and [hd1_status], 0 |
mov dword [esp+36], 2 ; not implemented |
ret |
fs_HdServices: |
dd fs_HdRead |
dd fs_HdReadFolder |
dd fs_HdRewrite |
dd fs_HdWrite |
dd fs_HdSetFileEnd |
dd fs_HdGetFileInfo |
dd fs_HdSetFileInfo |
dd 0 ;fs_HdExecute |
dd fs_HdDelete |
dd fs_HdCreateFolder |
fs_NumHdServices = ($ - fs_HdServices)/4 |
;******************************************************* |
fs_OnCd0: |
call reserve_cd |
mov [ChannelNumber],1 |
mov [DiskNumber],0 |
push 6 |
jmp fs_OnCd |
fs_OnCd1: |
call reserve_cd |
mov [ChannelNumber],1 |
mov [DiskNumber],1 |
push 4 |
jmp fs_OnCd |
fs_OnCd2: |
call reserve_cd |
mov [ChannelNumber],2 |
mov [DiskNumber],0 |
push 2 |
jmp fs_OnCd |
fs_OnCd3: |
call reserve_cd |
mov [ChannelNumber],2 |
mov [DiskNumber],1 |
push 0 |
fs_OnCd: |
call reserve_cd_channel |
pop eax |
mov [hdpos], eax |
cmp ecx, 0x100 |
jae .nf |
push ecx ebx |
mov cl,al |
mov bl,[0x40001] |
shr bl,cl |
test bl,2 |
pop ebx ecx |
jnz @f |
.nf: |
call free_cd_channel |
and [cd_status], 0 |
mov dword [esp+36], 5 ; not found |
ret |
@@: |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
add edx, std_application_base_address |
mov eax, [ebx] |
cmp eax,fs_NumCdServices |
jae .not_impl |
add ebx, 4 |
call dword [fs_CdServices + eax*4] |
call free_cd_channel |
and [cd_status], 0 |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
.not_impl: |
call free_cd_channel |
and [cd_status], 0 |
mov dword [esp+36], 2 ; not implemented |
ret |
fs_CdServices: |
dd fs_CdRead |
dd fs_CdReadFolder |
dd fs_NotImplemented |
dd fs_NotImplemented |
dd fs_NotImplemented |
dd fs_CdGetFileInfo |
dd fs_NotImplemented |
dd fs_CdExecute |
fs_NumCdServices = ($ - fs_CdServices)/4 |
;******************************************************* |
fs_HasRamdisk: |
mov al, 1 ; we always have ramdisk |
ret |
fs_HasFloppy: |
cmp byte [0x40000], 0 |
setnz al |
ret |
fs_HasHd0: |
mov al, [0x40001] |
and al, 11000000b |
cmp al, 01000000b |
setz al |
ret |
fs_HasHd1: |
mov al, [0x40001] |
and al, 00110000b |
cmp al, 00010000b |
setz al |
ret |
fs_HasHd2: |
mov al, [0x40001] |
and al, 00001100b |
cmp al, 00000100b |
setz al |
ret |
fs_HasHd3: |
mov al, [0x40001] |
and al, 00000011b |
cmp al, 00000001b |
setz al |
ret |
;******************************************************* |
fs_HasCd0: |
mov al, [0x40001] |
and al, 11000000b |
cmp al, 10000000b |
setz al |
ret |
fs_HasCd1: |
mov al, [0x40001] |
and al, 00110000b |
cmp al, 00100000b |
setz al |
ret |
fs_HasCd2: |
mov al, [0x40001] |
and al, 00001100b |
cmp al, 00001000b |
setz al |
ret |
fs_HasCd3: |
mov al, [0x40001] |
and al, 00000011b |
cmp al, 00000010b |
setz al |
ret |
;******************************************************* |
; fs_NextXXX functions: |
; in: eax = partition number, from which start to scan |
; out: CF=1 => no more partitions |
; CF=0 => eax=next partition number |
fs_NextRamdisk: |
; we always have /rd/1 |
test eax, eax |
stc |
jnz @f |
mov al, 1 |
clc |
@@: |
ret |
fs_NextFloppy: |
; we have /fd/1 iff (([0x40000] and 0xF0) != 0) and /fd/2 iff (([0x40000] and 0x0F) != 0) |
test byte [0x40000], 0xF0 |
jz .no1 |
test eax, eax |
jnz .no1 |
inc eax |
ret ; CF cleared |
.no1: |
test byte [0x40000], 0x0F |
jz .no2 |
cmp al, 2 |
jae .no2 |
mov al, 2 |
clc |
ret |
.no2: |
stc |
ret |
; on hdx, we have partitions from 1 to [0x40002+x] |
fs_NextHd0: |
push 0 |
jmp fs_NextHd |
fs_NextHd1: |
push 1 |
jmp fs_NextHd |
fs_NextHd2: |
push 2 |
jmp fs_NextHd |
fs_NextHd3: |
push 3 |
fs_NextHd: |
pop ecx |
movzx ecx, byte [0x40002+ecx] |
cmp eax, ecx |
jae fs_NextFloppy.no2 |
inc eax |
clc |
ret |
;******************************************************* |
fs_NextCd: |
; we always have /cdX/1 |
test eax, eax |
stc |
jnz @f |
mov al, 1 |
clc |
@@: |
ret |
;******************************************************* |
/kernel/tags/kolibri0.6.5.0/fs/ntfs.inc |
---|
0,0 → 1,1790 |
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 |
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 .okret |
sub eax, 0x200 |
add [ntfs_cur_read], eax |
jmp .okret |
.errread2: |
pop ecx |
add esp, 10h |
jmp .errret |
.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 |
ntfs_find_lfn: |
; in: esi->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 uni2ansi_char |
call char_toupper |
push eax |
mov al, [edi] |
inc edi |
call char_toupper |
cmp al, [esp] |
pop eax |
loopz @b |
jz .found |
pop edi |
pop esi |
jb .subnode |
.scanloopcont: |
movzx eax, word [esi+8] |
add esi, eax |
jmp .scanloopint |
.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 |
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 |
push ERROR_ACCESS_DENIED |
pop eax |
ret |
@@: |
call ntfs_find_lfn |
jnc .found |
or ebx, -1 |
push ERROR_FILE_NOT_FOUND |
pop eax |
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 |
push ERROR_ACCESS_DENIED |
pop eax |
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: |
push ERROR_END_OF_FILE |
pop eax |
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 |
push 12 |
pop eax |
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 |
; 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 |
push 2 |
pop eax |
ret |
@@: |
call ntfs_find_lfn |
jnc .doit |
push ERROR_FILE_NOT_FOUND |
pop eax |
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 |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/kernel/tags/kolibri0.6.5.0/fs/part_set.inc |
---|
0,0 → 1,444 |
;************************************************************* |
;* 29.04.2006 Elimination of hangup after the * |
;* expiration hd_wait_timeout - Mario79 * |
;* 28.01.2006 find all Fat16/32 partition in all input point * |
;* to MBR - Mario79 * |
;************************************************************* |
uglobal |
align 4 |
;****************************************************** |
; Please do not change this place - variables in text |
; Mario79 |
; START place |
;****************************************************** |
PARTITION_START dd 0x3f |
PARTITION_END dd 0 |
fs_type db 0 ; 0=none, 1=NTFS, 16=FAT16, 32=FAT32 |
align 4 |
fs_dependent_data_start: |
; FATxx data |
SECTORS_PER_FAT dd 0x1f3a |
NUMBER_OF_FATS dd 0x2 |
SECTORS_PER_CLUSTER dd 0x8 |
BYTES_PER_SECTOR dd 0x200 ; Note: if BPS <> 512 need lots of changes |
ROOT_CLUSTER dd 2 ; first rootdir cluster |
FAT_START dd 0 ; start of fat table |
ROOT_START dd 0 ; start of rootdir (only fat16) |
ROOT_SECTORS dd 0 ; count of rootdir sectors (only fat16) |
DATA_START dd 0 ; start of data area (=first cluster 2) |
LAST_CLUSTER dd 0 ; last availabe cluster |
ADR_FSINFO dd 0 ; used only by fat32 |
fatRESERVED dd 0x0FFFFFF6 |
fatBAD dd 0x0FFFFFF7 |
fatEND dd 0x0FFFFFF8 |
fatMASK dd 0x0FFFFFFF |
fs_dependent_data_end: |
file_system_data_size = $ - PARTITION_START |
if file_system_data_size > 96 |
ERROR: sizeof(file system data) too big! |
end if |
virtual at fs_dependent_data_start |
; NTFS data |
ntfs_data: |
.sectors_per_cluster dd ? |
.mft_cluster dd ? |
.mftmirr_cluster dd ? |
.frs_size dd ? ; FRS size in bytes |
.iab_size dd ? ; IndexAllocationBuffer size in bytes |
.frs_buffer dd ? |
.iab_buffer dd ? |
.mft_retrieval dd ? |
.mft_retrieval_size dd ? |
.mft_retrieval_alloc dd ? |
.mft_retrieval_end dd ? |
.cur_index_size dd ? |
.cur_index_buf dd ? |
if $ > fs_dependent_data_end |
ERROR: increase sizeof(fs_dependent_data)! |
end if |
end virtual |
;*************************************************************************** |
; End place |
; Mario79 |
;*************************************************************************** |
endg |
iglobal |
partition_types: ; list of fat16/32 partitions |
db 0x04 ; DOS: fat16 <32M |
db 0x06 ; DOS: fat16 >32M |
db 0x0b ; WIN95: fat32 |
db 0x0c ; WIN95: fat32, LBA-mapped |
db 0x0e ; WIN95: fat16, LBA-mapped |
db 0x14 ; Hidden DOS: fat16 <32M |
db 0x16 ; Hidden DOS: fat16 >32M |
db 0x1b ; Hidden WIN95: fat32 |
db 0x1c ; Hidden WIN95: fat32, LBA-mapped |
db 0x1e ; Hidden WIN95: fat16, LBA-mapped |
db 0xc4 ; DRDOS/secured: fat16 <32M |
db 0xc6 ; DRDOS/secured: fat16 >32M |
db 0xcb ; DRDOS/secured: fat32 |
db 0xcc ; DRDOS/secured: fat32, LBA-mapped |
db 0xce ; DRDOS/secured: fat16, LBA-mapped |
db 0xd4 ; Old Multiuser DOS secured: fat16 <32M |
db 0xd6 ; Old Multiuser DOS secured: fat16 >32M |
db 0x07 ; NTFS |
partition_types_end: |
extended_types: ; list of extended partitions |
db 0x05 ; DOS: extended partition |
db 0x0f ; WIN95: extended partition, LBA-mapped |
db 0xc5 ; DRDOS/secured: extended partition |
db 0xd5 ; Old Multiuser DOS secured: extended partition |
extended_types_end: |
endg |
; Partition chain used: |
; MBR ; PARTITION2 ; PARTITION3 ; PARTITION4 |
;========================================================== |
; fat16/32 +-- fat16/32 +-- fat16/32 +-- fat16/32 +-- |
; extended --+ extended --+ extended --+ extended --+ |
; 0 0 0 0 |
; 0 0 0 0 |
; Notes: |
; - extended partition need to be in second entry on table |
; - it will skip over removed partitions |
set_FAT32_variables: |
mov [problem_partition],0 |
call reserve_hd1 |
call reserve_hd_channel |
cmp dword [hdpos],0 |
je problem_hd |
pushad |
xor ecx,ecx ; partition count |
mov edx,-1 ; flag for partition |
xor eax,eax ; read MBR |
xor ebp,ebp ; extended partition start |
new_partition: |
test ebp,ebp ; is there extended partition? |
jnz extended_already_set ; yes |
xchg ebp,eax ; no. set it now |
extended_already_set: |
add eax,ebp ; mbr=mbr+0, ext_part=ext_start+relat_start |
mov ebx,buffer |
call hd_read |
cmp [hd_error],0 |
jne problem_hd |
cmp word [ebx+0x1fe],0xaa55 ; is it valid boot sector? |
jnz end_partition_chain |
cmp dword [ebx+0x1be+0xc],0 ; skip over empty partition |
jz next_partition |
push eax |
mov al,[ebx+0x1be+4] ; get primary partition type |
call scan_partition_types |
pop eax |
jnz next_primary_partition ; no. skip over |
inc ecx |
cmp ecx,[fat32part] ; is it wanted partition? |
jnz next_primary_partition ; no |
mov edx, eax ; start sector |
add edx, [ebx+0x1be+8] ; add relative start |
push edx |
add edx, [ebx+0x1be+12] ; add length |
dec edx ; PARTITION_END is inclusive |
mov [PARTITION_END], edx ; note that this can be changed |
; when file system data will be available |
mov dl, [ebx+0x1be+4] |
mov [fs_type], dl ; save for FS recognizer (separate FAT vs NTFS) |
pop edx |
next_primary_partition: |
push eax |
mov al,[ebx+0x1be+4+16] ; get primary partition type |
call scan_partition_types |
pop eax |
jnz next_primary_partition_1 ; no. skip over |
inc ecx |
cmp ecx,[fat32part] ; is it wanted partition? |
jnz next_primary_partition_1 ; no |
mov edx, eax |
add edx, [ebx+0x1be+8+16] |
push edx |
add edx, [ebx+0x1be+12+16] |
dec edx |
mov [PARTITION_END], edx |
mov dl, [ebx+0x1be+4+16] |
mov [fs_type], dl |
pop edx |
next_primary_partition_1: |
push eax |
mov al,[ebx+0x1be+4+16+16] ; get primary partition type |
call scan_partition_types |
pop eax |
jnz next_primary_partition_2 ; no. skip over |
inc ecx |
cmp ecx,[fat32part] ; is it wanted partition? |
jnz next_primary_partition_2 ; no |
mov edx, eax |
add edx, [ebx+0x1be+8+16+16] |
push edx |
add edx, [ebx+0x1be+12+16+16] |
dec edx |
mov [PARTITION_END], edx |
mov dl, [ebx+0x1be+4+16+16] |
mov [fs_type], dl |
pop edx |
next_primary_partition_2: |
push eax |
mov al,[ebx+0x1be+4+16+16+16] ; get primary partition type |
call scan_partition_types |
pop eax |
jnz next_partition ; no. skip over |
inc ecx |
cmp ecx,[fat32part] ; is it wanted partition? |
jnz next_partition ; no |
mov edx, eax |
add edx, [ebx+0x1be+8+16+16+16] |
push edx |
add edx, [ebx+0x1be+12+16+16+16] |
dec edx |
mov [PARTITION_END], edx |
mov dl, [ebx+0x1be+4+16+16+16] |
mov [fs_type], dl |
pop edx |
next_partition: |
push eax |
mov al,[ebx+0x1be+4] ; get extended partition type |
call scan_extended_types |
pop eax |
jnz next_partition_1 |
mov eax,[ebx+0x1be+8] ; add relative start |
test eax,eax ; is there extended partition? |
jnz new_partition ; yes. read it |
next_partition_1: |
push eax |
mov al,[ebx+0x1be+4+16] ; get extended partition type |
call scan_extended_types |
pop eax |
jnz next_partition_2 |
mov eax,[ebx+0x1be+8+16] ; add relative start |
test eax,eax ; is there extended partition? |
jnz new_partition ; yes. read it |
next_partition_2: |
push eax |
mov al,[ebx+0x1be+4+16+16] ; get extended partition type |
call scan_extended_types |
pop eax |
jnz next_partition_3 |
mov eax,[ebx+0x1be+8+16+16] ; add relative start |
test eax,eax ; is there extended partition? |
jnz new_partition ; yes. read it |
next_partition_3: |
push eax |
mov al,[ebx+0x1be+4+16+16+16] ; get extended partition type |
call scan_extended_types |
pop eax |
jnz end_partition_chain ; no. end chain |
mov eax,[ebx+0x1be+8+16+16+16] ; get start of extended partition |
test eax,eax ; is there extended partition? |
jnz new_partition ; yes. read it |
end_partition_chain: |
mov [partition_count],ecx |
cmp edx,-1 ; found wanted partition? |
jnz hd_and_partition_ok ; yes. install it |
jmp problem_partition_or_fat |
scan_partition_types: |
push ecx |
mov edi,partition_types |
mov ecx,partition_types_end-partition_types |
cld |
repne scasb ; is partition type ok? |
pop ecx |
ret |
scan_extended_types: |
push ecx |
mov edi,extended_types |
mov ecx,extended_types_end-extended_types |
cld |
repne scasb ; is it extended partition? |
pop ecx |
ret |
problem_fat_dec_count: ; bootsector is missing or another problem |
dec [partition_count] ; remove it from partition_count |
problem_partition_or_fat: |
popad |
problem_hd: |
mov [fs_type],0 |
call free_hd_channel |
mov [hd1_status],0 ; free |
mov [problem_partition],1 |
ret |
hd_and_partition_ok: |
mov eax,edx |
mov [PARTITION_START],eax |
mov edx, [PARTITION_END] |
sub edx, eax |
inc edx ; edx = length of partition |
; mov [hd_setup],1 |
mov ebx,buffer |
call hd_read ; read boot sector of partition |
cmp [hd_error], 0 |
jz boot_read_ok |
cmp [fs_type], 7 |
jnz problem_fat_dec_count |
; NTFS duplicates bootsector: |
; NT4/2k/XP+ saves bootsector copy in the end of disk |
; NT 3.51 saves bootsector copy in the middle of disk |
and [hd_error], 0 |
mov eax, [PARTITION_END] |
call hd_read |
cmp [hd_error], 0 |
jnz @f |
call ntfs_test_bootsec |
jnc boot_read_ok |
@@: |
and [hd_error], 0 |
mov eax, edx |
shr eax, 1 |
add eax, [PARTITION_START] |
call hd_read |
cmp [hd_error], 0 |
jnz problem_fat_dec_count ; ¥ áã¤ì¡ ... |
boot_read_ok: |
; mov [hd_setup], 0 |
; if we are running on NTFS, check bootsector |
cmp [fs_type], 7 |
jz ntfs_setup |
cmp word [ebx+0x1fe],0xaa55 ; is it valid boot sector? |
jnz problem_fat_dec_count |
movzx eax,word [ebx+0xe] ; sectors reserved |
add eax,[PARTITION_START] |
mov [FAT_START],eax ; fat_start = partition_start + reserved |
movzx eax,byte [ebx+0xd] ; sectors per cluster |
mov [SECTORS_PER_CLUSTER],eax |
movzx ecx,word [ebx+0xb] ; bytes per sector |
mov [BYTES_PER_SECTOR],ecx |
movzx eax,word [ebx+0x11] ; count of rootdir entries (=0 fat32) |
mov edx,32 |
mul edx |
dec ecx |
add eax,ecx ; round up if not equal count |
inc ecx ; bytes per sector |
div ecx |
mov [ROOT_SECTORS],eax ; count of rootdir sectors |
movzx eax,word [ebx+0x16] ; sectors per fat <65536 |
test eax,eax |
jnz fat16_fatsize |
mov eax,[ebx+0x24] ; sectors per fat |
fat16_fatsize: |
mov [SECTORS_PER_FAT],eax |
movzx eax,byte [ebx+0x10] ; number of fats |
test eax,eax ; if 0 it's not fat partition |
jz problem_fat_dec_count |
mov [NUMBER_OF_FATS],eax |
imul eax,[SECTORS_PER_FAT] |
add eax,[FAT_START] |
mov [ROOT_START],eax ; rootdir = fat_start + fat_size * fat_count |
add eax,[ROOT_SECTORS] ; rootdir sectors should be 0 on fat32 |
mov [DATA_START],eax ; data area = rootdir + rootdir_size |
movzx eax,word [ebx+0x13] ; total sector count <65536 |
test eax,eax |
jnz fat16_total |
mov eax,[ebx+0x20] ; total sector count |
fat16_total: |
add eax,[PARTITION_START] |
dec eax |
mov [PARTITION_END],eax |
inc eax |
sub eax,[DATA_START] ; eax = count of data sectors |
xor edx,edx |
div dword [SECTORS_PER_CLUSTER] |
inc eax |
mov [LAST_CLUSTER],eax |
dec eax ; cluster count |
; limits by Microsoft Hardware White Paper v1.03 |
cmp eax,4085 ; 0xff5 |
jb problem_fat_dec_count ; fat12 not supported |
cmp eax,65525 ; 0xfff5 |
jb fat16_partition |
fat32_partition: |
mov eax,[ebx+0x2c] ; rootdir cluster |
mov [ROOT_CLUSTER],eax |
movzx eax,word [ebx+0x30] ; fs info sector |
add eax,[PARTITION_START] |
mov [ADR_FSINFO],eax |
popad |
mov [fatRESERVED],0x0FFFFFF6 |
mov [fatBAD],0x0FFFFFF7 |
mov [fatEND],0x0FFFFFF8 |
mov [fatMASK],0x0FFFFFFF |
mov [fs_type],32 ; Fat32 |
call free_hd_channel |
mov [hd1_status],0 ; free |
ret |
fat16_partition: |
xor eax,eax |
mov [ROOT_CLUSTER],eax |
popad |
mov [fatRESERVED],0x0000FFF6 |
mov [fatBAD],0x0000FFF7 |
mov [fatEND],0x0000FFF8 |
mov [fatMASK],0x0000FFFF |
mov [fs_type],16 ; Fat16 |
call free_hd_channel |
mov [hd1_status],0 ; free |
ret |
/kernel/tags/kolibri0.6.5.0/fs/iso9660.inc |
---|
0,0 → 1,823 |
uglobal |
cd_current_pointer_of_input dd 0 |
cd_current_pointer_of_input_2 dd 0 |
cd_mem_location dd 0 |
cd_counter_block dd 0 |
IDE_Channel_1 db 0 |
IDE_Channel_2 db 0 |
endg |
CDDataBuf equ 0x7000 |
reserve_cd: |
cli |
cmp [cd_status],0 |
je reserve_ok2 |
sti |
call change_task |
jmp reserve_cd |
reserve_ok2: |
push eax |
mov eax,[0x3000] |
shl eax,5 |
mov eax,[eax+0x3000+TASKDATA.pid] |
mov [cd_status],eax |
pop eax |
sti |
ret |
reserve_cd_channel: |
cmp [ChannelNumber],1 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
cli |
cmp [IDE_Channel_1],0 |
je .reserve_ok_1 |
sti |
call change_task |
jmp .IDE_Channel_1 |
.IDE_Channel_2: |
cli |
cmp [IDE_Channel_2],0 |
je .reserve_ok_2 |
sti |
call change_task |
jmp .IDE_Channel_1 |
.reserve_ok_1: |
mov [IDE_Channel_1],1 |
ret |
.reserve_ok_2: |
mov [IDE_Channel_2],1 |
ret |
free_cd_channel: |
cmp [ChannelNumber],1 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
mov [IDE_Channel_1],0 |
ret |
.IDE_Channel_2: |
mov [IDE_Channel_2],0 |
ret |
cd_status dd 0 |
;---------------------------------------------------------------- |
; |
; fs_CdRead - LFN variant for reading CD disk |
; |
; esi points to filename /dir1/dir2/.../dirn/file,0 |
; 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 |
; |
;-------------------------------------------------------------- |
fs_CdRead: |
push edi |
cmp byte [esi], 0 |
jnz @f |
.noaccess: |
pop edi |
.noaccess_2: |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.noaccess_3: |
pop eax edx ecx edi |
jmp .noaccess_2 |
@@: |
call cd_find_lfn |
jnc .found |
pop edi |
cmp [DevErrorCode],0 |
jne .noaccess_2 |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
mov edi,[cd_current_pointer_of_input] |
test byte [edi+25],10b ; do not allow read directories |
jnz .noaccess |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
mov eax, 6 ; end of file |
pop edi |
ret |
@@: |
mov ebx, [ebx] |
.l1: |
push ecx edx |
push 0 |
mov eax, [edi+10] ; ðåàëüíûé ðàçìåð ôàéëîâîé ñåêöèè |
sub eax, ebx |
jb .eof |
cmp eax, ecx |
jae @f |
mov ecx, eax |
mov byte [esp], 6 |
@@: |
mov eax,[edi+2] |
mov [CDSectorAddress],eax |
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data |
.new_sector: |
test ecx, ecx |
jz .done |
sub ebx, 2048 |
jae .next |
add ebx, 2048 |
jnz .incomplete_sector |
cmp ecx, 2048 |
jb .incomplete_sector |
; we may read and memmove complete sector |
mov [CDDataBuf_pointer],edx |
call ReadCDWRetr ; ÷èòàåì ñåêòîð ôàéëà |
cmp [DevErrorCode],0 |
jne .noaccess_3 |
add edx, 2048 |
sub ecx, 2048 |
.next: |
inc dword [CDSectorAddress] |
jmp .new_sector |
.incomplete_sector: |
; we must read and memmove incomplete sector |
mov [CDDataBuf_pointer],CDDataBuf |
call ReadCDWRetr ; ÷èòàåì ñåêòîð ôàéëà |
cmp [DevErrorCode],0 |
jne .noaccess_3 |
push ecx |
add ecx, ebx |
cmp ecx, 2048 |
jbe @f |
mov ecx, 2048 |
@@: |
sub ecx, ebx |
push edi esi ecx |
mov edi,edx |
lea esi, [CDDataBuf + ebx] |
cld |
rep movsb |
pop ecx esi edi |
add edx, ecx |
sub [esp], ecx |
pop ecx |
xor ebx, ebx |
jmp .next |
.done: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx ecx |
sub ebx, edx |
jmp .reteof |
;---------------------------------------------------------------- |
; |
; fs_CdReadFolder - LFN variant for reading CD disk folder |
; |
; esi points to filename /dir1/dir2/.../dirn/file,0 |
; 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 |
; |
;-------------------------------------------------------------- |
fs_CdReadFolder: |
push edi |
call cd_find_lfn |
jnc .found |
pop edi |
cmp [DevErrorCode],0 |
jne .noaccess_1 |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
mov edi,[cd_current_pointer_of_input] |
test byte [edi+25],10b ; do not allow read directories |
jnz .found_dir |
pop edi |
.noaccess_1: |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
mov eax,[edi+2] ; eax=cluster |
mov [CDSectorAddress],eax |
mov eax,[edi+10] ; ðàçìåð äèðåêòðîðèè |
.doit: |
; init header |
push eax ecx |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
pop ecx eax |
mov byte [edx], 1 ; version |
mov [cd_mem_location],edx |
add [cd_mem_location],32 |
; íà÷èíàåì ïåðåáðîñêó ÁÄÂÊ â ÓÑÂÊ |
;.mainloop: |
mov [cd_counter_block],dword 0 |
dec dword [CDSectorAddress] |
push ecx |
.read_to_buffer: |
inc dword [CDSectorAddress] |
mov [CDDataBuf_pointer],CDDataBuf |
call ReadCDWRetr ; ÷èòàåì ñåêòîð äèðåêòîðèè |
cmp [DevErrorCode],0 |
jne .noaccess_1 |
call .get_names_from_buffer |
sub eax,2048 |
; äèðåêòîðèÿ çàêîí÷èëàñü? |
cmp eax,0 |
ja .read_to_buffer |
mov edi,[cd_counter_block] |
mov [edx+8],edi |
mov edi,[ebx] |
sub [edx+4],edi |
pop ecx edi |
mov ebx, [edx+4] |
mov eax,ERROR_SUCCESS |
ret |
.get_names_from_buffer: |
mov [cd_current_pointer_of_input_2],CDDataBuf |
push eax esi edi edx |
.get_names_from_buffer_1: |
call cd_get_name |
jc .end_buffer |
inc dword [cd_counter_block] |
mov eax,[cd_counter_block] |
cmp [ebx],eax |
jae .get_names_from_buffer_1 |
test ecx, ecx |
jz .get_names_from_buffer_1 |
mov edi,[cd_counter_block] |
mov [edx+4],edi |
dec ecx |
mov esi,ebp |
mov edi,[cd_mem_location] |
add edi,40 |
test dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE |
jnz .unicode |
; jmp .unicode |
.ansi: |
cmp [cd_counter_block],2 |
jbe .ansi_parent_directory |
cld |
lodsw |
xchg ah,al |
call uni2ansi_char |
cld |
stosb |
; ïðîâåðêà êîíöà ôàéëà |
mov ax,[esi] |
cmp ax,word 3B00h ; ñåïàðàòîð êîíöà ôàéëà ';' |
je .cd_get_parameters_of_file_1 |
; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì |
movzx eax,byte [ebp-33] |
add eax,ebp |
sub eax,34 |
cmp esi,eax |
je .cd_get_parameters_of_file_1 |
; ïðîâåðêà êîíöà ïàïêè |
movzx eax,byte [ebp-1] |
add eax,ebp |
cmp esi,eax |
jb .ansi |
.cd_get_parameters_of_file_1: |
mov [edi],byte 0 |
call cd_get_parameters_of_file |
add [cd_mem_location],304 |
jmp .get_names_from_buffer_1 |
.ansi_parent_directory: |
cmp [cd_counter_block],2 |
je @f |
mov [edi],byte '.' |
inc edi |
jmp .cd_get_parameters_of_file_1 |
@@: |
mov [edi],word '..' |
add edi,2 |
jmp .cd_get_parameters_of_file_1 |
.unicode: |
cmp [cd_counter_block],2 |
jbe .unicode_parent_directory |
cld |
movsw |
; ïðîâåðêà êîíöà ôàéëà |
mov ax,[esi] |
cmp ax,word 3B00h ; ñåïàðàòîð êîíöà ôàéëà ';' |
je .cd_get_parameters_of_file_2 |
; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì |
movzx eax,byte [ebp-33] |
add eax,ebp |
sub eax,34 |
cmp esi,eax |
je .cd_get_parameters_of_file_2 |
; ïðîâåðêà êîíöà ïàïêè |
movzx eax,byte [ebp-1] |
add eax,ebp |
cmp esi,eax |
jb .unicode |
.cd_get_parameters_of_file_2: |
mov [edi],word 0 |
call cd_get_parameters_of_file |
add [cd_mem_location],560 |
jmp .get_names_from_buffer_1 |
.unicode_parent_directory: |
cmp [cd_counter_block],2 |
je @f |
mov [edi],word 2E00h ; '.' |
add edi,2 |
jmp .cd_get_parameters_of_file_2 |
@@: |
mov [edi],dword 2E002E00h ; '..' |
add edi,4 |
jmp .cd_get_parameters_of_file_2 |
.end_buffer: |
pop edx edi esi eax |
ret |
cd_get_parameters_of_file: |
mov edi,[cd_mem_location] |
cd_get_parameters_of_file_1: |
; ïîëó÷àåì àòðèáóòû ôàéëà |
xor eax,eax |
; ôàéë íå àðõèâèðîâàëñÿ |
inc al |
shl eax,1 |
; ýòî êàòàëîã? |
test [ebp-8],byte 2 |
jz .file |
inc al |
.file: |
; ìåòêà òîìà íå êàê â FAT, â ýòîì âèäå îòñóòñâóåò |
; ôàéë íå ÿâëÿåòñÿ ñèñòåìíûì |
shl eax,3 |
; ôàéë ÿâëÿåòñÿ ñêðûòûì? (àòðèáóò ñóùåñòâîâàíèå) |
test [ebp-8],byte 1 |
jz .hidden |
inc al |
.hidden: |
shl eax,1 |
; ôàéë âñåãäà òîëüêî äëÿ ÷òåíèÿ, òàê êàê ýòî CD |
inc al |
mov [edi],eax |
; ïîëó÷àåì âðåìÿ äëÿ ôàéëà |
;÷àñ |
movzx eax,byte [ebp-12] |
shl eax,8 |
;ìèíóòà |
mov al,[ebp-11] |
shl eax,8 |
;ñåêóíäà |
mov al,[ebp-10] |
;âðåìÿ ñîçäàíèÿ ôàéëà |
mov [edi+8],eax |
;âðåìÿ ïîñëåäíåãî äîñòóïà |
mov [edi+16],eax |
;âðåìÿ ïîñëåäíåé çàïèñè |
mov [edi+24],eax |
; ïîëó÷àåì äàòó äëÿ ôàéëà |
;ãîä |
movzx eax,byte [ebp-15] |
add eax,1900 |
shl eax,8 |
;ìåñÿö |
mov al,[ebp-14] |
shl eax,8 |
;äåíü |
mov al,[ebp-13] |
;äàòà ñîçäàíèÿ ôàéëà |
mov [edi+12],eax |
;âðåìÿ ïîñëåäíåãî äîñòóïà |
mov [edi+20],eax |
;âðåìÿ ïîñëåäíåé çàïèñè |
mov [edi+28],eax |
; ïîëó÷àåì òèï äàííûõ èìåíè |
xor eax,eax |
test dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE |
jnz .unicode_1 |
mov [edi+4],eax |
jmp @f |
.unicode_1: |
inc eax |
mov [edi+4],eax |
@@: |
; ïîëó÷àåì ðàçìåð ôàéëà â áàéòàõ |
xor eax,eax |
mov [edi+32+4],eax |
mov eax,[ebp-23] |
mov [edi+32],eax |
ret |
;---------------------------------------------------------------- |
; |
; fs_CdGetFileInfo - LFN variant for CD |
; get file/directory attributes structure |
; |
;---------------------------------------------------------------- |
fs_CdGetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi ebp |
call cd_find_lfn |
pushfd |
cmp [DevErrorCode], 0 |
jz @f |
popfd |
pop ebp edi |
mov eax, 11 |
ret |
@@: |
popfd |
jnc @f |
pop ebp edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
mov edi, edx |
call cd_get_parameters_of_file_1 |
and dword [edi+4], 0 |
pop ebp edi |
xor eax, eax |
ret |
;---------------------------------------------------------------- |
; |
; fs_CdExecute - LFN variant for executing from CD |
; |
; esi points to hd filename (e.g. 'dir1/name') |
; ebp points to full filename (e.g. '/hd0/1/dir1/name') |
; dword [ebx] = flags |
; dword [ebx+4] = cmdline |
; |
; ret ebx,edx destroyed |
; eax > 0 - PID, < 0 - error |
; |
;-------------------------------------------------------------- |
fs_CdExecute: |
mov edx, [ebx] |
mov ebx, [ebx+4] |
test ebx, ebx |
jz @f |
add ebx, std_application_base_address |
@@: |
;---------------------------------------------------------------- |
; |
; fs_CdExecute.flags - second entry |
; |
; esi points to floppy filename (kernel address) |
; ebp points to full filename |
; edx flags |
; ebx cmdline (kernel address) |
; |
; ret eax > 0 - PID, < 0 - error |
; |
;-------------------------------------------------------------- |
.flags: |
cmp byte [esi], 0 |
jnz @f |
; cannot execute root! |
mov eax, -ERROR_ACCESS_DENIED |
ret |
@@: |
push edi |
call cd_find_lfn |
jnc .found |
pop edi |
mov eax, -ERROR_FILE_NOT_FOUND |
cmp [DevErrorCode], 0 |
jz @f |
mov al, -11 |
@@: |
ret |
.found: |
mov edi,[cd_current_pointer_of_input] |
mov eax,[edi+2] |
push 0 |
push eax |
push dword [edi+10] ; size |
push .DoRead |
call fs_execute |
add esp, 16 |
pop edi |
ret |
.DoRead: |
; read next block |
; in: eax->parameters, edi->buffer |
; out: eax = error code |
pushad |
cmp dword [eax], 0 ; file size |
jz .eof |
cmp [eax+8],dword 0 |
jne @f |
mov ecx,[eax+4] |
inc dword [eax+4] |
mov [CDSectorAddress],ecx |
mov [CDDataBuf_pointer],CDDataBuf ;edi |
call ReadCDWRetr |
cmp [DevErrorCode], 0 |
jnz .err |
@@: |
push esi edi ecx |
mov esi,512 |
imul esi,[eax+8] |
add esi,CDDataBuf |
mov ecx,512/4 |
cld |
rep movsd |
pop ecx edi esi |
mov eax, [esp+28] |
mov ecx, [eax] |
sub ecx, 512 |
jae @f |
lea edi, [edi+ecx+512] |
neg ecx |
push eax |
xor eax, eax |
rep stosb |
pop eax |
@@: |
mov [eax], ecx |
mov edx, [eax+8] |
inc edx |
cmp edx, 4 ; 2048/512=4 |
jb @f |
xor edx, edx |
@@: |
mov [eax+8], edx |
popad |
xor eax, eax |
ret |
.eof: |
popad |
mov eax, 6 |
ret |
.err: |
popad |
mov eax, 11 |
ret |
cd_find_lfn: |
; in: esi->name |
; out: CF=1 - file not found |
; else CF=0 and [cd_current_pointer_of_input] direntry |
push eax esi |
; 16 ñåêòîð íà÷àëî íàáîðà äåñêðèïòîðîâ òîìîâ |
mov [CDSectorAddress],dword 15 |
.start: |
inc dword [CDSectorAddress] |
mov [CDDataBuf_pointer],CDDataBuf |
call ReadCDWRetr |
cmp [DevErrorCode],0 |
jne .access_denied |
; ïðîâåðêà íà âøèâîñòü |
cmp [CDDataBuf+1],dword 'CD00' |
jne .access_denied |
cmp [CDDataBuf+5],byte '1' |
jne .access_denied |
; ñåêòîð ÿâëÿåòñÿ òåðìèíàòîðîì íàáîð äåñêðèïòîðîâ òîìîâ? |
cmp [CDDataBuf],byte 0xff |
je .access_denied |
; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì è óëó÷øåííûì äåñêðèïòîðîì òîìà? |
cmp [CDDataBuf],byte 0x2 |
jne .start |
; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì äåñêðèïòîðîì òîìà? |
cmp [CDDataBuf+6],byte 0x1 |
jne .start |
; ïàðàìåòðû root äèðåêòðîðèè |
mov eax,[CDDataBuf+0x9c+2] ; íà÷àëî root äèðåêòðîðèè |
mov [CDSectorAddress],eax |
mov eax,[CDDataBuf+0x9c+10] ; ðàçìåð root äèðåêòðîðèè |
cmp byte [esi], 0 |
jnz @f |
mov [cd_current_pointer_of_input],CDDataBuf+0x9c |
jmp .done |
@@: |
; íà÷èíàåì ïîèñê |
.mainloop: |
dec dword [CDSectorAddress] |
.read_to_buffer: |
inc dword [CDSectorAddress] |
mov [CDDataBuf_pointer],CDDataBuf |
call ReadCDWRetr ; ÷èòàåì ñåêòîð äèðåêòîðèè |
cmp [DevErrorCode],0 |
jne .access_denied |
call cd_find_name_in_buffer |
jnc .found |
sub eax,2048 |
; äèðåêòîðèÿ çàêîí÷èëàñü? |
cmp eax,0 |
ja .read_to_buffer |
; íåò èñêîìîãî ýëåìåíòà öåïî÷êè |
.access_denied: |
pop esi eax |
stc |
ret |
; èñêîìûé ýëåìåíò öåïî÷êè íàéäåí |
.found: |
; êîíåö ïóòè ôàéëà |
cmp byte [esi-1], 0 |
jz .done |
mov eax,[cd_current_pointer_of_input] |
add eax,2 |
mov eax,[eax] |
mov [CDSectorAddress],eax ; íà÷àëî äèðåêòîðèè |
add eax,8 |
mov eax,[eax] ; ðàçìåð äèðåêòîðèè |
jmp .mainloop |
; óêàçàòåëü ôàéëà íàéäåí |
.done: |
pop esi eax |
clc |
ret |
cd_find_name_in_buffer: |
mov [cd_current_pointer_of_input_2],CDDataBuf |
.start: |
call cd_get_name |
jc .not_found |
call cd_compare_name |
jc .start |
.found: |
clc |
ret |
.not_found: |
stc |
ret |
cd_get_name: |
push eax |
mov ebp,[cd_current_pointer_of_input_2] |
mov [cd_current_pointer_of_input],ebp |
mov eax,[ebp] |
cmp eax,0 ; âõîäû çàêîí÷èëèñü? |
je .next_sector |
cmp ebp,CDDataBuf+2048 ; áóôåð çàêîí÷èëñÿ? |
jae .next_sector |
movzx eax, byte [ebp] |
add [cd_current_pointer_of_input_2],eax ; ñëåäóþùèé âõîä êàòàëîãà |
add ebp,33 ; óêàçàòåëü óñòàíîâëåí íà íà÷àëî èìåíè |
pop eax |
clc |
ret |
.next_sector: |
pop eax |
stc |
ret |
cd_compare_name: |
; compares ASCIIZ-names, case-insensitive (cp866 encoding) |
; in: esi->name, ebp->name |
; out: if names match: ZF=1 and esi->next component of name |
; else: ZF=0, esi is not changed |
; destroys eax |
push esi eax edi |
mov edi,ebp |
.loop: |
cld |
lodsb |
push ax |
call char_todown |
call ansi2uni_char |
xchg ah,al |
cld |
scasw |
pop ax |
je .coincides |
call char_toupper |
call ansi2uni_char |
xchg ah,al |
cld |
sub edi,2 |
scasw |
jne .name_not_coincide |
.coincides: |
cmp [esi],byte '/' ; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà |
je .done |
cmp [esi],byte 0 ; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà |
je .done |
jmp .loop |
.name_not_coincide: |
pop edi eax esi |
stc |
ret |
.done: |
; ïðîâåðêà êîíöà ôàéëà |
cmp [edi],word 3B00h ; ñåïàðàòîð êîíöà ôàéëà ';' |
je .done_1 |
; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì |
movzx eax,byte [ebp-33] |
add eax,ebp |
sub eax,34 |
cmp edi,eax |
je .done_1 |
; ïðîâåðêà êîíöà ïàïêè |
movzx eax,byte [ebp-1] |
add eax,ebp |
cmp edi,eax |
jne .name_not_coincide |
.done_1: |
pop edi eax |
add esp,4 |
inc esi |
clc |
ret |
char_todown: |
; convert character to uppercase, using cp866 encoding |
; in: al=symbol |
; out: al=converted symbol |
cmp al, 'A' |
jb .ret |
cmp al, 'Z' |
jbe .az |
cmp al, '' |
jb .ret |
cmp al, '' |
jb .rus1 |
cmp al, '' |
ja .ret |
; 0x90-0x9F -> 0xE0-0xEF |
add al, 'à'-'' |
.ret: |
ret |
.rus1: |
; 0x80-0x8F -> 0xA0-0xAF |
.az: |
add al, 0x20 |
ret |
uni2ansi_char: |
; convert UNICODE character in al to ANSI character in ax, using cp866 encoding |
; in: ax=UNICODE character |
; out: al=converted ANSI character |
cmp ax, 0x80 |
jb .ascii |
cmp ax, 0x401 |
jz .yo1 |
cmp ax, 0x451 |
jz .yo2 |
cmp ax, 0x410 |
jb .unk |
cmp ax, 0x440 |
jb .rus1 |
cmp ax, 0x450 |
jb .rus2 |
.unk: |
mov al, '_' |
jmp .doit |
.yo1: |
mov al, 'ð' |
jmp .doit |
.yo2: |
mov al, 'ñ' |
jmp .doit |
.rus1: |
; 0x410-0x43F -> 0x80-0xAF |
add al, 0x70 |
jmp .doit |
.rus2: |
; 0x440-0x44F -> 0xE0-0xEF |
add al, 0xA0 |
.ascii: |
.doit: |
ret |