forked from KolibriOS/kolibrios
334f7721de
2) Are deleted CLI and STI from procedures of reading and writing of sector on HDD. These of commands are replaced by operation with a port [hdbase]+206h, which disables only interruption for IDE. git-svn-id: svn://kolibrios.org@136 a494cfbc-eb01-0410-851d-a64ba20cac60
4184 lines
106 KiB
PHP
4184 lines
106 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; ;;
|
||
;; FAT32.INC ;;
|
||
;; ;;
|
||
;; FAT16/32 functions for KolibriOS ;;
|
||
;; ;;
|
||
;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;;
|
||
;; ;;
|
||
;; See file COPYING for details ;;
|
||
;; 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]
|
||
|
||
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
|
||
|
||
fat_in_cache dd -1
|
||
fat_cache: times 512 db 0
|
||
|
||
uglobal
|
||
Sector512: ; label for dev_hdcd.inc
|
||
buffer: times 512 db 0
|
||
deltree_buffer: times 512 db 0
|
||
fsinfo_buffer: times 512 db 0
|
||
endg
|
||
|
||
iglobal
|
||
NewDirEntry1 db ". ",0x10
|
||
times 20 db 0
|
||
NewDirEntry2 db ".. ",0x10
|
||
times 20 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
|
||
;********************************************
|
||
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_1
|
||
.reserve_ok_1:
|
||
mov [IDE_Channel_1],1
|
||
ret
|
||
.reserve_ok_2:
|
||
mov [IDE_Channel_2],1
|
||
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
|
||
;********************************************
|
||
clear_hd_cache:
|
||
|
||
push eax ecx edi
|
||
mov edi,0x600000
|
||
mov ecx,16384
|
||
xor eax,eax
|
||
cld
|
||
rep stosd ; clear hd cache with 0
|
||
mov [cache_search_start],eax
|
||
mov [fat_in_cache],-1
|
||
mov [fat_change],0
|
||
pop edi ecx eax
|
||
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 [fat_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 [fat_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 [fat_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 [fat_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 [fat_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 [fat_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
|
||
|
||
|
||
makedir:
|
||
;-----------------------------------------------------
|
||
; input : eax = directory name
|
||
; edx = path
|
||
; output : eax = 0 - ok
|
||
; 3 - unknown FS
|
||
; 5 - file not found
|
||
; 8 - disk full
|
||
; 10 - access denied
|
||
; Note : can only make one directory at time
|
||
;-----------------------------------------------------
|
||
cmp [fat_type],0
|
||
jnz make_dir_fat_ok
|
||
mov eax,ERROR_UNKNOWN_FS
|
||
ret
|
||
|
||
make_dir_fat_ok:
|
||
; call reserve_hd1
|
||
|
||
pushad
|
||
|
||
mov ebx,edx
|
||
call get_cluster_of_a_path
|
||
jnc make_dir_found_path
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
|
||
make_dir_path_not_found:
|
||
popad
|
||
call update_disk ; write all of cache and fat to hd
|
||
cmp [hd_error],0
|
||
jne make_dir_error_2
|
||
|
||
mov [hd1_status],0
|
||
mov eax,ERROR_FILE_NOT_FOUND
|
||
ret
|
||
|
||
make_dir_disk_full:
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
popad
|
||
call update_disk ; write all of cache and fat to hd
|
||
cmp [hd_error],0
|
||
jne make_dir_error_2
|
||
|
||
mov [hd1_status],0
|
||
mov eax,ERROR_DISK_FULL
|
||
ret
|
||
|
||
make_dir_already_exist:
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
mov eax,[cluster] ; directory cluster
|
||
xor edx,edx ; free
|
||
call set_FAT
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
|
||
popad
|
||
call update_disk ; write all of cache and fat to hd
|
||
make_dir_error_2:
|
||
mov [hd1_status],0
|
||
mov eax,ERROR_ACCESS_DENIED
|
||
ret
|
||
|
||
make_dir_error_1:
|
||
popad
|
||
jmp make_dir_error_2
|
||
|
||
make_dir_error_3:
|
||
add esp,4
|
||
jmp make_dir_error_1
|
||
|
||
make_dir_found_path:
|
||
cmp eax,[ROOT_CLUSTER]
|
||
jnz make_dir_not_root
|
||
xor eax,eax
|
||
|
||
make_dir_not_root:
|
||
mov ecx,eax ; directorys start cluster
|
||
mov word [NewDirEntry2+26],cx ; 16 bits low of cluster
|
||
shr ecx,16
|
||
mov word [NewDirEntry2+20],cx ; 16 bits high of cluster (=0 fat16)
|
||
|
||
push eax ; save parent directory cluster
|
||
mov eax,2
|
||
call get_free_FAT
|
||
mov [cluster],eax ; first free cluster
|
||
pop eax
|
||
jc make_dir_disk_full
|
||
|
||
push eax
|
||
mov eax,[cluster] ; directory cluster
|
||
mov edx,[fatEND] ; end for directory
|
||
call set_FAT
|
||
cmp [hd_error],0
|
||
jne make_dir_error_3
|
||
pop eax
|
||
|
||
mov ebx,PUSHAD_EAX ; dir name
|
||
push eax
|
||
call analyze_directory ; check if directory already exist
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
|
||
pop eax
|
||
jnc make_dir_already_exist ; need to free allocated cluster!
|
||
|
||
call analyze_directory_to_write
|
||
jc make_dir_already_exist ; need to free allocated cluster!
|
||
|
||
mov esi,PUSHAD_EAX ; dir name
|
||
mov edi,ebx ; pointer in buffer
|
||
mov ecx,11
|
||
cld
|
||
rep movsb
|
||
|
||
mov dword [ebx+28],0 ; dir size is always 0
|
||
mov ecx,[cluster]
|
||
mov [ebx+26],cx ; 16 bits low of cluster
|
||
mov word [NewDirEntry1+26],cx
|
||
shr ecx,16
|
||
mov [ebx+20],cx ; 16 bits high of cluster (=0 fat16)
|
||
mov word [NewDirEntry1+20],cx
|
||
mov byte [ebx+11],0x10 ; attribute = directory
|
||
|
||
call set_current_time_for_entry
|
||
mov ecx,[ebx+22]
|
||
mov dword [NewDirEntry1+22],ecx
|
||
mov dword [NewDirEntry2+22],ecx
|
||
|
||
mov ebx,buffer ; save the directory name,length,cluster
|
||
call hd_write
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
|
||
mov ecx,512/4
|
||
xor eax,eax
|
||
mov edi,buffer
|
||
cld
|
||
rep stosd ; clear new directory cluster
|
||
|
||
mov eax,[cluster] ; new directory cluster
|
||
sub eax,2
|
||
mov edx,[SECTORS_PER_CLUSTER]
|
||
imul eax,edx
|
||
add eax,[DATA_START]
|
||
mov ebx,buffer
|
||
add eax,edx ; start from last sector
|
||
|
||
dir_set_empty_directory:
|
||
dec eax ; next sector
|
||
cmp edx,1 ; is first directory sector?
|
||
jnz not_first_sector ; no. write empty sector
|
||
mov esi,NewDirEntry1
|
||
mov edi,buffer
|
||
mov ecx,64/4
|
||
cld
|
||
rep movsd ; copy 2 first directory entrys "." and ".."
|
||
|
||
not_first_sector:
|
||
call hd_write
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
|
||
dec edx
|
||
jnz dir_set_empty_directory
|
||
|
||
mov ecx,-1 ; remove 1 cluster from free disk space
|
||
call add_disk_free_space
|
||
cmp [hd_error],0
|
||
jne make_dir_error_1
|
||
|
||
popad
|
||
call update_disk ; write all of cache and fat to hd
|
||
cmp [hd_error],0
|
||
jne make_dir_error_2
|
||
mov [hd1_status],0
|
||
xor eax,eax
|
||
ret
|
||
|
||
|
||
removedir:
|
||
;-----------------------------------------------------
|
||
; input : eax = file/directory name
|
||
; edx = path
|
||
; output : eax = 0 - ok
|
||
; 3 - unknown FS
|
||
; 5 - file not found
|
||
; 10 - access denied
|
||
;-----------------------------------------------------
|
||
cmp [fat_type],0
|
||
jnz remove_dir_fat_ok
|
||
mov eax,ERROR_UNKNOWN_FS
|
||
ret
|
||
|
||
remove_dir_fat_ok:
|
||
; call reserve_hd1
|
||
|
||
push edi
|
||
mov edi,1 ; allow directory remove
|
||
call file_delete
|
||
cmp [hd_error],0
|
||
jne @f
|
||
|
||
pop edi
|
||
|
||
call update_disk ; write all of cache and fat to hd
|
||
@@:
|
||
mov [hd1_status],0
|
||
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 [fat_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 [fat_type],0
|
||
jnz fat_ok_for_writing
|
||
mov eax,ERROR_UNKNOWN_FS
|
||
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 [fat_type],0
|
||
jnz 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 [fat_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 [fat_type],0
|
||
jnz file_del_fat_ok
|
||
mov eax,ERROR_UNKNOWN_FS
|
||
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?
|
||
jz delete_notdir ; no. it's file
|
||
cmp edi,1 ; allow directory remove
|
||
jnz delete_no_access ; no
|
||
|
||
push eax ; save directory sector
|
||
mov eax,[ebx+20-2] ; first cluster of file
|
||
mov ax,[ebx+26] ; 0 length files start cluster = 0
|
||
and eax,[fatMASK]
|
||
xor ebp,ebp ; counter for directory deepnes
|
||
call clear_directory
|
||
pop eax
|
||
jc delete_no_access
|
||
|
||
push ebx ; save directory pointer in buffer
|
||
mov ebx,buffer
|
||
call hd_read ; read directory sector
|
||
cmp [hd_error],0
|
||
jne delete_no_access_1
|
||
pop ebx
|
||
|
||
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
|
||
|
||
|
||
clear_directory:
|
||
;-----------------------------------------------------
|
||
; input : eax = directory cluster
|
||
; ebp = directory deepnes
|
||
; Note : use recursive call
|
||
;-----------------------------------------------------
|
||
pushad
|
||
inc ebp
|
||
cmp ebp,64 ; if over 63 directory deep
|
||
jnb clear_error ; something must be wrong
|
||
|
||
clear_new_cluster:
|
||
cmp eax,[LAST_CLUSTER]
|
||
ja clear_end
|
||
cmp eax,[ROOT_CLUSTER] ; don't remove root cluster
|
||
jz clear_end
|
||
mov esi,eax ; esi = current directory cluster
|
||
sub eax,2
|
||
jb clear_end
|
||
mov ecx,[SECTORS_PER_CLUSTER]
|
||
imul eax,ecx
|
||
add eax,[DATA_START]
|
||
|
||
clear_new_sector:
|
||
mov edi,eax ; edi = current directory sector
|
||
mov ebx,deltree_buffer
|
||
call hd_read
|
||
cmp [hd_error],0
|
||
jne clear_error
|
||
|
||
mov edx,512/32 ; count of dir entrys per sector = 16
|
||
|
||
clear_analyze:
|
||
mov al,[ebx+11] ; file attribute
|
||
and al,0xf
|
||
cmp al,0xf
|
||
je clear_long_filename
|
||
|
||
cmp byte [ebx],'.' ; parent or current directory
|
||
je clear_next_entry
|
||
cmp byte [ebx],0xe5 ; deleted
|
||
je clear_next_entry
|
||
cmp byte [ebx],0 ; empty
|
||
je clear_write_last
|
||
;je clear_next_entry
|
||
|
||
mov eax,[ebx+20-2] ; first cluster of entry
|
||
mov ax,[ebx+26]
|
||
and eax,[fatMASK]
|
||
|
||
test byte [ebx+11],0x10 ; is it directory?
|
||
jz clear_file ; no
|
||
|
||
push eax ebx
|
||
mov eax,edi
|
||
mov ebx,deltree_buffer ; save buffer over recursive call
|
||
call hd_write ; write directory sector to disk
|
||
cmp [hd_error],0
|
||
jne clear_error
|
||
|
||
pop ebx eax
|
||
|
||
call clear_directory ; recursive call !!!
|
||
jc clear_error ; exit if error found
|
||
|
||
push eax ebx
|
||
mov eax,edi
|
||
mov ebx,deltree_buffer
|
||
call hd_read ; read directory sector again
|
||
cmp [hd_error],0
|
||
jne clear_error_1
|
||
|
||
pop ebx eax
|
||
|
||
clear_file:
|
||
call clear_cluster_chain
|
||
cmp [hd_error],0
|
||
jne clear_error
|
||
|
||
clear_long_filename:
|
||
mov byte [ebx],0xe5
|
||
|
||
clear_next_entry:
|
||
add ebx,32 ; position of next dir entry
|
||
dec edx
|
||
jnz clear_analyze
|
||
|
||
mov eax,edi
|
||
mov ebx,deltree_buffer
|
||
call hd_write ; write directory sector to disk
|
||
cmp [hd_error],0
|
||
jne clear_error
|
||
|
||
inc eax ; next sector
|
||
dec ecx
|
||
jnz clear_new_sector
|
||
|
||
mov eax,esi
|
||
call get_FAT ; get next cluster
|
||
cmp [hd_error],0
|
||
jne clear_error
|
||
|
||
jmp clear_new_cluster ; clear it
|
||
|
||
clear_write_last:
|
||
mov eax,edi
|
||
mov ebx,deltree_buffer
|
||
call hd_write ; write directory sector to disk
|
||
cmp [hd_error],0
|
||
jne clear_error
|
||
|
||
clear_end:
|
||
popad
|
||
clc
|
||
ret
|
||
clear_error_1:
|
||
add esp,8
|
||
clear_error:
|
||
popad
|
||
stc
|
||
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
|
||
|
||
|
||
rename:
|
||
;-----------------------------------------------------------
|
||
; input : eax = source directory name
|
||
; edx = source path
|
||
; ebx = dest directory name
|
||
; edi = dest path
|
||
; output : eax = 0 - ok
|
||
; 3 - unknown FS
|
||
; 5 - file not found
|
||
; 8 - disk full
|
||
; 10 - access denied
|
||
;-----------------------------------------------------------
|
||
cmp [fat_type],0
|
||
jnz fat_ok_for_rename
|
||
mov eax,ERROR_UNKNOWN_FS
|
||
ret
|
||
|
||
fat_ok_for_rename:
|
||
; call reserve_hd1
|
||
|
||
pushad
|
||
|
||
mov ebx,edx ; source path
|
||
call get_cluster_of_a_path
|
||
jc rename_entry_not_found
|
||
|
||
mov ebx,PUSHAD_EAX ; source directory name
|
||
call analyze_directory
|
||
jc rename_entry_not_found
|
||
|
||
mov [sector_tmp],eax ; save source sector
|
||
mov [entry_pos],ebx
|
||
mov esi,ebx
|
||
mov edi,dir_entry
|
||
mov ecx,32/4
|
||
cld
|
||
rep movsd ; save entry
|
||
|
||
mov ebx,PUSHAD_EDI ; dest path
|
||
call get_cluster_of_a_path
|
||
jc rename_entry_not_found
|
||
|
||
mov edx,eax ; save dest directory cluster
|
||
mov ebx,PUSHAD_EBX ; dest directory name
|
||
push [longname_sec1]
|
||
push [longname_sec2]
|
||
call analyze_directory ; check if entry already exist
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist_1
|
||
|
||
pop [longname_sec2]
|
||
pop [longname_sec1]
|
||
jnc rename_entry_already_exist
|
||
|
||
mov eax,edx
|
||
call analyze_directory_to_write
|
||
jc rename_disk_full
|
||
|
||
mov esi,dir_entry
|
||
mov edi,ebx
|
||
mov ecx,32/4
|
||
cld
|
||
rep movsd ; copy entry
|
||
mov esi,PUSHAD_EBX ; dest directory name
|
||
mov edi,ebx
|
||
mov ecx,11
|
||
rep movsb ; copy name
|
||
|
||
mov ebx,buffer ; save the directory name,length,cluster
|
||
call hd_write
|
||
|
||
test byte [dir_entry+11],0x10 ; is it directory?
|
||
jz rename_not_dir ; no
|
||
mov eax,[dir_entry+20-2] ; FAT entry
|
||
mov ax,[dir_entry+26]
|
||
and eax,[fatMASK]
|
||
call change_2dot_cluster
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist
|
||
|
||
rename_not_dir:
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist
|
||
mov eax,[sector_tmp]
|
||
mov ebx,buffer
|
||
call hd_read ; read source directory sector
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist
|
||
|
||
mov ebx,[entry_pos]
|
||
call delete_entry_name
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist
|
||
|
||
popad
|
||
call update_disk ; write all of cache and fat to hd
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist_2
|
||
mov [hd1_status],0
|
||
xor eax,eax
|
||
ret
|
||
|
||
rename_entry_not_found:
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist
|
||
popad
|
||
mov [hd1_status],0
|
||
mov eax,ERROR_FILE_NOT_FOUND
|
||
ret
|
||
|
||
rename_entry_already_exist_1:
|
||
add esp,8
|
||
rename_entry_already_exist:
|
||
popad
|
||
rename_entry_already_exist_2:
|
||
mov [hd1_status],0
|
||
mov eax,ERROR_ACCESS_DENIED
|
||
ret
|
||
|
||
rename_disk_full:
|
||
cmp [hd_error],0
|
||
jne rename_entry_already_exist
|
||
popad
|
||
mov [hd1_status],0
|
||
mov eax,ERROR_DISK_FULL
|
||
ret
|
||
|
||
|
||
change_2dot_cluster:
|
||
;-----------------------------------------------------------
|
||
; input : eax = directory cluster
|
||
; edx = value to save
|
||
; change : eax,ebx,edx
|
||
;-----------------------------------------------------------
|
||
cmp eax,[LAST_CLUSTER]
|
||
ja not_2dot ; too big cluster number, something is wrong
|
||
sub eax,2
|
||
jb not_2dot
|
||
|
||
imul eax,[SECTORS_PER_CLUSTER]
|
||
add eax,[DATA_START]
|
||
mov ebx,buffer
|
||
call hd_read
|
||
cmp [hd_error],0
|
||
jne not_2dot
|
||
|
||
cmp dword [ebx+32],'.. '
|
||
jnz not_2dot
|
||
|
||
cmp edx,[ROOT_CLUSTER] ; is rootdir cluster?
|
||
jne not_2dot_root
|
||
xor edx,edx ; yes. set it zero
|
||
|
||
not_2dot_root:
|
||
mov [ebx+32+26],dx ; 16 bits low of cluster
|
||
shr edx,16
|
||
mov [ebx+32+20],dx ; 16 bits high of cluster (=0 fat16)
|
||
call hd_write
|
||
|
||
not_2dot:
|
||
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 [fat_type],0
|
||
jnz 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
|
||
|
||
|
||
;**************************************************************************
|
||
;
|
||
; 0x600008 - first entry in cache list
|
||
;
|
||
; +0 - lba sector
|
||
; +4 - state of cache sector
|
||
; 0 = empty
|
||
; 1 = used for read ( same as in hd )
|
||
; 2 = used for write ( differs from hd )
|
||
;
|
||
; +65536 - cache entries
|
||
;
|
||
;**************************************************************************
|
||
|
||
|
||
hd_read:
|
||
;-----------------------------------------------------------
|
||
; input : eax = block to read
|
||
; ebx = destination
|
||
;-----------------------------------------------------------
|
||
push ecx esi edi ; scan cache
|
||
|
||
mov ecx,cache_max ; entries in cache
|
||
mov esi,0x600000+8
|
||
mov edi,1
|
||
|
||
hdreadcache:
|
||
|
||
cmp dword [esi+4],0 ; empty
|
||
je nohdcache
|
||
|
||
cmp [esi],eax ; correct sector
|
||
je yeshdcache
|
||
|
||
nohdcache:
|
||
|
||
add esi,8
|
||
inc edi
|
||
dec ecx
|
||
jnz hdreadcache
|
||
|
||
call find_empty_slot ; ret in edi
|
||
cmp [hd_error],0
|
||
jne return_01
|
||
|
||
push eax edx
|
||
|
||
call disable_ide_int
|
||
|
||
call wait_for_hd_idle
|
||
cmp [hd_error],0
|
||
jne hd_read_error
|
||
|
||
; cli
|
||
xor eax,eax
|
||
mov edx,[hdbase]
|
||
inc edx
|
||
out dx,al ; ATAFeatures ॣ<><E0A5A3><EFBFBD><EFBFBD> "<22>ᮡ<EFBFBD><E1AEA1><EFBFBD><EFBFBD><EFBFBD>⥩"
|
||
inc edx
|
||
inc eax
|
||
out dx,al ; ATASectorCount <20><><EFBFBD><EFBFBD>稪 ᥪ<><E1A5AA>
|
||
inc edx
|
||
mov eax,[esp+4]
|
||
out dx,al ; ATASectorNumber ॣ<><E0A5A3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ᥪ<><E1A5AA><EFBFBD><EFBFBD>
|
||
shr eax,8
|
||
inc edx
|
||
out dx,al ; ATACylinder <20><><EFBFBD><EFBFBD><EFBFBD> 樫<><E6A8AB><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD>訩 <20><><EFBFBD><EFBFBD>)
|
||
shr eax,8
|
||
inc edx
|
||
out dx,al ; <20><><EFBFBD><EFBFBD><EFBFBD> 樫<><E6A8AB><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD>訩 <20><><EFBFBD><EFBFBD>)
|
||
shr eax,8
|
||
inc edx
|
||
and al,1+2+4+8
|
||
add al,byte [hdid]
|
||
add al,128+64+32
|
||
out dx,al ; <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD> <20><>᪠
|
||
inc edx
|
||
mov al,20h
|
||
out dx,al ; ATACommand ॣ<><E0A5A3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; sti
|
||
|
||
call wait_for_sector_buffer
|
||
|
||
cmp [hd_error],0
|
||
jne hd_read_error
|
||
|
||
; cli
|
||
push edi
|
||
shl edi,9
|
||
add edi,0x600000+65536
|
||
mov ecx,256
|
||
mov edx,[hdbase]
|
||
cld
|
||
rep insw
|
||
pop edi
|
||
; sti
|
||
|
||
call enable_ide_int
|
||
|
||
pop edx eax
|
||
blok_read_2:
|
||
lea esi,[edi*8+0x600000]
|
||
mov [esi],eax ; sector number
|
||
mov dword [esi+4],1 ; hd read - mark as same as in hd
|
||
|
||
yeshdcache:
|
||
|
||
mov esi,edi
|
||
shl esi,9
|
||
add esi,0x600000+65536
|
||
mov edi,ebx
|
||
mov ecx,512/4
|
||
cld
|
||
rep movsd ; move data
|
||
return_01:
|
||
pop edi esi ecx
|
||
ret
|
||
|
||
disable_ide_int:
|
||
mov edx,[hdbase]
|
||
add edx,0x206
|
||
mov al,2
|
||
out dx,al
|
||
ret
|
||
|
||
enable_ide_int:
|
||
mov edx,[hdbase]
|
||
add edx,0x206
|
||
mov al,0
|
||
out dx,al
|
||
ret
|
||
|
||
hd_write:
|
||
;-----------------------------------------------------------
|
||
; input : eax = block
|
||
; ebx = pointer to memory
|
||
;-----------------------------------------------------------
|
||
push ecx esi edi
|
||
|
||
; check if the cache already has the sector and overwrite it
|
||
|
||
mov ecx,cache_max
|
||
mov esi,0x600000+8
|
||
mov edi,1
|
||
|
||
hdwritecache:
|
||
|
||
cmp dword [esi+4],0 ; if cache slot is empty
|
||
je not_in_cache_write
|
||
|
||
cmp [esi],eax ; if the slot has the sector
|
||
je yes_in_cache_write
|
||
|
||
not_in_cache_write:
|
||
|
||
add esi,8
|
||
inc edi
|
||
dec ecx
|
||
jnz hdwritecache
|
||
|
||
; sector not found in cache
|
||
; write the block to a new location
|
||
|
||
call find_empty_slot ; ret in edi
|
||
cmp [hd_error],0
|
||
jne hd_write_access_denied
|
||
|
||
lea esi,[edi*8+0x600000]
|
||
mov [esi],eax ; sector number
|
||
|
||
yes_in_cache_write:
|
||
|
||
mov dword [esi+4],2 ; write - differs from hd
|
||
|
||
shl edi,9
|
||
add edi,0x600000+65536
|
||
mov esi,ebx
|
||
mov ecx,512/4
|
||
cld
|
||
rep movsd ; move data
|
||
hd_write_access_denied:
|
||
pop edi esi ecx
|
||
ret
|
||
|
||
|
||
write_cache:
|
||
;-----------------------------------------------------------
|
||
; write all changed sectors to disk
|
||
;-----------------------------------------------------------
|
||
push eax ecx edx esi edi
|
||
|
||
; write difference ( 2 ) from cache to hd
|
||
|
||
mov ecx,cache_max
|
||
mov esi,0x600000+8
|
||
mov edi,1
|
||
|
||
write_cache_more:
|
||
|
||
cmp dword [esi+4],2 ; if cache slot is not different
|
||
jne does_not_need_writing
|
||
|
||
mov dword [esi+4],1 ; same as in hd
|
||
mov eax,[esi] ; eax = sector to write
|
||
|
||
cmp eax,[PARTITION_START]
|
||
jb danger
|
||
cmp eax,[PARTITION_END]
|
||
ja danger
|
||
|
||
call disable_ide_int
|
||
|
||
call wait_for_hd_idle
|
||
cmp [hd_error],0
|
||
jne hd_write_error
|
||
|
||
; cli
|
||
xor eax,eax
|
||
mov edx,[hdbase]
|
||
inc edx
|
||
out dx,al
|
||
inc edx
|
||
inc eax
|
||
out dx,al
|
||
inc edx
|
||
mov eax,[esi] ; eax = sector to write
|
||
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,byte [hdid]
|
||
add al,128+64+32
|
||
out dx,al
|
||
inc edx
|
||
mov al,30h
|
||
out dx,al
|
||
; sti
|
||
|
||
call wait_for_sector_buffer
|
||
|
||
cmp [hd_error],0
|
||
jne hd_write_error
|
||
|
||
push ecx esi
|
||
|
||
; cli
|
||
mov esi,edi
|
||
shl esi,9
|
||
add esi,0x600000+65536 ; esi = from memory position
|
||
mov ecx,256
|
||
mov edx,[hdbase]
|
||
cld
|
||
rep outsw
|
||
; sti
|
||
|
||
pop esi ecx
|
||
|
||
call enable_ide_int
|
||
|
||
danger:
|
||
does_not_need_writing:
|
||
|
||
add esi,8
|
||
inc edi
|
||
dec ecx
|
||
jnz write_cache_more
|
||
return_02:
|
||
pop edi esi edx ecx eax
|
||
ret
|
||
|
||
|
||
find_empty_slot:
|
||
;-----------------------------------------------------------
|
||
; find empty or read slot, flush cache if next 10% is used by write
|
||
; output : edi = cache slot
|
||
;-----------------------------------------------------------
|
||
push ecx esi
|
||
|
||
search_again:
|
||
|
||
mov ecx,cache_max*10/100
|
||
mov edi,[cache_search_start]
|
||
|
||
search_for_empty:
|
||
|
||
inc edi
|
||
cmp edi,cache_max
|
||
jbe inside_cache
|
||
mov edi,1
|
||
|
||
inside_cache:
|
||
|
||
cmp dword [edi*8+0x600000+4],2 ; get cache slot info
|
||
jb found_slot ; it's empty or read
|
||
dec ecx
|
||
jnz search_for_empty
|
||
|
||
call write_cache ; no empty slots found, write all
|
||
cmp [hd_error],0
|
||
jne found_slot_access_denied
|
||
|
||
jmp search_again ; and start again
|
||
|
||
found_slot:
|
||
|
||
mov [cache_search_start],edi
|
||
found_slot_access_denied:
|
||
pop esi ecx
|
||
ret
|
||
|
||
|
||
save_hd_wait_timeout:
|
||
|
||
push eax
|
||
mov eax,[timer_ticks];[0xfdf0]
|
||
add eax,300 ; 3 sec timeout
|
||
mov [hd_wait_timeout],eax
|
||
pop eax
|
||
ret
|
||
|
||
|
||
check_hd_wait_timeout:
|
||
|
||
push eax
|
||
mov eax,[hd_wait_timeout]
|
||
cmp [timer_ticks], eax ;[0xfdf0],eax
|
||
jg hd_timeout_error
|
||
pop eax
|
||
mov [hd_error],0
|
||
ret
|
||
|
||
iglobal
|
||
hd_timeout_str db 'K : FS - HD timeout',13,10,0
|
||
hd_read_str db 'K : FS - HD read error',13,10,0
|
||
hd_write_str db 'K : FS - HD write error',13,10,0
|
||
hd_lba_str db 'K : FS - HD LBA error',13,10,0
|
||
endg
|
||
|
||
hd_timeout_error:
|
||
|
||
call clear_hd_cache
|
||
call clear_application_table_status
|
||
mov esi,hd_timeout_str
|
||
call sys_msg_board_str
|
||
; jmp $
|
||
mov [hd_error],1
|
||
pop eax
|
||
ret
|
||
|
||
hd_read_error:
|
||
|
||
call clear_hd_cache
|
||
call clear_application_table_status
|
||
mov esi,hd_read_str
|
||
call sys_msg_board_str
|
||
pop edx eax
|
||
jmp return_01
|
||
; jmp $
|
||
|
||
hd_write_error:
|
||
|
||
call clear_hd_cache
|
||
call clear_application_table_status
|
||
mov esi,hd_write_str
|
||
call sys_msg_board_str
|
||
jmp return_02
|
||
; jmp $
|
||
|
||
hd_lba_error:
|
||
call clear_hd_cache
|
||
call clear_application_table_status
|
||
mov esi,hd_lba_str
|
||
call sys_msg_board_str
|
||
jmp LBA_read_ret
|
||
|
||
|
||
wait_for_hd_idle:
|
||
|
||
push eax edx
|
||
|
||
call save_hd_wait_timeout
|
||
|
||
mov edx,[hdbase]
|
||
add edx,0x7
|
||
|
||
wfhil1:
|
||
|
||
call check_hd_wait_timeout
|
||
cmp [hd_error],0
|
||
jne @f
|
||
|
||
in al,dx
|
||
test al,128
|
||
jnz wfhil1
|
||
|
||
@@:
|
||
|
||
pop edx eax
|
||
ret
|
||
|
||
|
||
|
||
wait_for_sector_buffer:
|
||
|
||
push eax edx
|
||
|
||
mov edx,[hdbase]
|
||
add edx,0x7
|
||
|
||
call save_hd_wait_timeout
|
||
|
||
hdwait_sbuf: ; wait for sector buffer to be ready
|
||
|
||
call check_hd_wait_timeout
|
||
cmp [hd_error],0
|
||
jne @f
|
||
|
||
in al,dx
|
||
test al,8
|
||
jz hdwait_sbuf
|
||
|
||
mov [hd_error],0
|
||
|
||
cmp [hd_setup],1 ; do not mark error for setup request
|
||
je buf_wait_ok
|
||
|
||
test al,1 ; previous command ended up with an error
|
||
jz buf_wait_ok
|
||
@@:
|
||
mov [hd_error],1
|
||
|
||
buf_wait_ok:
|
||
|
||
pop edx eax
|
||
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 [fat_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 [fat_type], 0
|
||
jnz @f
|
||
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:
|
||
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 [fat_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 ecx
|
||
mov ecx, [eax+4]
|
||
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 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_HdRewrite:
|
||
cmp [fat_type], 0
|
||
jz 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 [fat_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:
|
||
; 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; must not be directory
|
||
test byte [edi+11], 10h
|
||
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
|
||
.doit:
|
||
lea eax, [esp+8]
|
||
call dword [eax+16] ; flush directory
|
||
push ecx
|
||
mov ecx, [esp+4+32+24]
|
||
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:
|
||
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
|
||
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
|
||
|
||
;----------------------------------------------------------------
|
||
;
|
||
; fs_HdWrite - 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
|
||
;
|
||
;--------------------------------------------------------------
|
||
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 [fat_type], 0
|
||
jnz @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:
|
||
; 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 eax
|
||
; copy new data
|
||
push eax
|
||
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
|
||
; 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 [fat_type], 0
|
||
jnz @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 [fat_type], 0
|
||
jnz @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 [fat_type], 0
|
||
jnz @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
|
||
|
||
;----------------------------------------------------------------
|
||
;
|
||
; 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{diamond}
|