;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;; FAT32.INC ;; ;; ;; ;; FAT16/32 functions for KolibriOS ;; ;; ;; ;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;; ;; ;; ;; See file COPYING for details ;; ;; 04.02.2007 LFN create folder - diamond ;; ;; 08.10.2006 LFN delete file/folder - diamond ;; ;; 20.08.2006 LFN set file size (truncate/extend) - diamond ;; ;; 17.08.2006 LFN write/append to file - diamond ;; ;; 23.06.2006 LFN start application - diamond ;; ;; 15.06.2006 LFN get/set file/folder info - diamond ;; ;; 27.05.2006 LFN create/rewrite file - diamond ;; ;; 04.05.2006 LFN read folder - diamond ;; ;; 29.04.2006 Elimination of hangup after the ;; ;; expiration hd_wait_timeout - Mario79 ;; ;; 23.04.2006 LFN read file - diamond ;; ;; 28.01.2006 find all Fat16/32 partition in all input point ;; ;; to MBR, see file part_set.inc - Mario79 ;; ;; 15.01.2005 get file size/attr/date, file_append - ATV ;; ;; 04.12.2004 skip volume label, file delete bug fixed - ATV ;; ;; 29.11.2004 get_free_FAT changed, append dir bug fixed - ATV ;; ;; 23.11.2004 don't allow overwrite dir with file - ATV ;; ;; 18.11.2004 get_disk_info and more error codes - ATV ;; ;; 17.11.2004 set_FAT/get_FAT and disk cache rewritten - ATV ;; ;; 10.11.2004 removedir clear whole directory structure - ATV ;; ;; 08.11.2004 rename - ATV ;; ;; 30.10.2004 file_read return also dirsize in bytes - ATV ;; ;; 20.10.2004 Makedir/Removedir - ATV ;; ;; 14.10.2004 Partition chain/Fat16 - ATV (thanks drh3xx) ;; ;; 06.9.2004 Fix free space by Mario79 added - MH ;; ;; 24.5.2004 Write back buffer for File_write -VT ;; ;; 20.5.2004 File_read function to work with syscall 58 - VT ;; ;; 30.3.2004 Error parameters at function return - VT ;; ;; 01.5.2002 Bugfix in device write - VT ;; ;; 20.5.2002 Hd status check - VT ;; ;; 29.6.2002 Improved fat32 verification - VT ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision$ cache_max equ 1919 ; max. is 1919*512+0x610000=0x6ffe00 ERROR_SUCCESS = 0 ERROR_DISK_BASE = 1 ERROR_UNSUPPORTED_FS = 2 ERROR_UNKNOWN_FS = 3 ERROR_PARTITION = 4 ERROR_FILE_NOT_FOUND = 5 ERROR_END_OF_FILE = 6 ERROR_MEMORY_POINTER = 7 ERROR_DISK_FULL = 8 ERROR_FAT_TABLE = 9 ERROR_ACCESS_DENIED = 10 PUSHAD_EAX equ [esp+28] PUSHAD_ECX equ [esp+24] PUSHAD_EDX equ [esp+20] PUSHAD_EBX equ [esp+16] PUSHAD_EBP equ [esp+8] PUSHAD_ESI equ [esp+4] PUSHAD_EDI equ [esp+0] uglobal align 4 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 cache_search_start dd 0 ; used by find_empty_slot endg iglobal fat_in_cache dd -1 endg uglobal align 4 fat_cache: times 512 db 0 Sector512: ; label for dev_hdcd.inc buffer: times 512 db 0 fsinfo_buffer: times 512 db 0 endg uglobal 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,[CURRENT_TASK] shl eax,5 mov eax,[eax+CURRENT_TASK+TASKDATA.pid] mov [hd1_status],eax pop eax sti ret ;******************************************** uglobal hd_in_cache db ? endg reserve_hd_channel: ; BIOS disk accesses are protected with common mutex hd1_status ; This must be modified when hd1_status will not be valid! cmp [hdpos], 0x80 jae .ret cmp [hdbase], 0x1F0 jne .IDE_Channel_2 .IDE_Channel_1: cli cmp [IDE_Channel_1],0 je .reserve_ok_1 sti call change_task jmp .IDE_Channel_1 .IDE_Channel_2: cli cmp [IDE_Channel_2],0 je .reserve_ok_2 sti call change_task jmp .IDE_Channel_2 .reserve_ok_1: mov [IDE_Channel_1], 1 push eax mov al, 1 jmp @f .reserve_ok_2: mov [IDE_Channel_2], 1 push eax mov al, 3 @@: cmp [hdid], 1 sbb al, -1 cmp al, [hd_in_cache] jz @f mov [hd_in_cache], al call clear_hd_cache @@: pop eax .ret: ret free_hd_channel: ; see comment at reserve_hd_channel cmp [hdpos], 0x80 jae .ret cmp [hdbase], 0x1F0 jne .IDE_Channel_2 .IDE_Channel_1: mov [IDE_Channel_1],0 .ret: ret .IDE_Channel_2: mov [IDE_Channel_2],0 ret ;******************************************** problem_partition db 0 ; used for partitions search include 'part_set.inc' set_FAT: ;-------------------------------- ; input : EAX = cluster ; EDX = value to save ; output : EDX = old value ;-------------------------------- push eax ebx esi cmp eax,2 jb sfc_error cmp eax,[LAST_CLUSTER] ja sfc_error cmp [fs_type],16 je sfc_1 add eax,eax sfc_1: add eax,eax mov esi,511 and esi,eax ; esi = position in fat sector shr eax,9 ; eax = fat sector add eax,[FAT_START] mov ebx,fat_cache cmp eax,[fat_in_cache] ; is fat sector already in memory? je sfc_in_cache ; yes cmp [fat_change],0 ; is fat changed? je sfc_no_change ; no call write_fat_sector ; yes. write it into disk cmp [hd_error],0 jne sfc_error sfc_no_change: mov [fat_in_cache],eax ; save fat sector call hd_read cmp [hd_error],0 jne sfc_error sfc_in_cache: cmp [fs_type],16 jne sfc_test32 sfc_set16: xchg [ebx+esi],dx ; save new value and get old value jmp sfc_write sfc_test32: mov eax,[fatMASK] sfc_set32: and edx,eax xor eax,-1 ; mask for high bits and eax,[ebx+esi] ; get high 4 bits or eax,edx mov edx,[ebx+esi] ; get old value mov [ebx+esi],eax ; save new value sfc_write: mov [fat_change],1 ; fat has changed sfc_nonzero: and edx,[fatMASK] sfc_error: pop esi ebx eax ret get_FAT: ;-------------------------------- ; input : EAX = cluster ; output : EAX = next cluster ;-------------------------------- push ebx esi cmp [fs_type],16 je gfc_1 add eax,eax gfc_1: add eax,eax mov esi,511 and esi,eax ; esi = position in fat sector shr eax,9 ; eax = fat sector add eax,[FAT_START] mov ebx,fat_cache cmp eax,[fat_in_cache] ; is fat sector already in memory? je gfc_in_cache cmp [fat_change],0 ; is fat changed? je gfc_no_change ; no call write_fat_sector ; yes. write it into disk cmp [hd_error],0 jne hd_error_01 gfc_no_change: mov [fat_in_cache],eax call hd_read cmp [hd_error],0 jne hd_error_01 gfc_in_cache: mov eax,[ebx+esi] and eax,[fatMASK] hd_error_01: pop esi ebx ret get_free_FAT: ;----------------------------------------------------------- ; 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 mov eax,[fatStartScan] cmp eax,2 jb gff_reset gff_test: cmp eax,[LAST_CLUSTER] ; if above last cluster start at cluster 2 jbe gff_in_range gff_reset: 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: lea ecx,[eax+1] mov [fatStartScan],ecx pop ecx clc ret write_fat_sector: ;----------------------------------------------------------- ; write changed fat to disk ;----------------------------------------------------------- push eax ebx ecx mov [fat_change],0 mov eax,[fat_in_cache] cmp eax,-1 jz write_fat_not_used mov ebx,fat_cache mov ecx,[NUMBER_OF_FATS] write_next_fat: call hd_write cmp [hd_error],0 jne write_fat_not_used add eax,[SECTORS_PER_FAT] dec ecx jnz write_next_fat write_fat_not_used: pop ecx ebx eax ret analyze_directory: ;----------------------------------------------------------- ; input : EAX = first cluster of the directory ; EBX = pointer to filename ; output : IF CARRY=0 EAX = sector where th file is found ; EBX = pointer in buffer ; [buffer .. buffer+511] ; ECX,EDX,ESI,EDI not changed ; IF CARRY=1 filename not found ; Note : if cluster=0 it's changed to read rootdir ; save 2 previous directory sectors in longname_sec ;----------------------------------------------------------- push ecx edx esi edi ebx ; ebx = [esp+0] mov [longname_sec1],0 mov [longname_sec2],0 adr_new_cluster: mov [cluster_tmp],eax mov [fat16_root],0 cmp eax,[LAST_CLUSTER] ja adr_not_found ; too big cluster number, something is wrong cmp eax,2 jnb adr_data_cluster mov eax,[ROOT_CLUSTER] ; if cluster < 2 then read rootdir cmp [fs_type],16 jne adr_data_cluster mov eax,[ROOT_START] mov edx,[ROOT_SECTORS] mov [fat16_root],1 ; flag for fat16 rootdir jmp adr_new_sector adr_data_cluster: sub eax,2 mov edx,[SECTORS_PER_CLUSTER] imul eax,edx add eax,[DATA_START] adr_new_sector: mov ebx,buffer call hd_read cmp [hd_error],0 jne adr_not_found mov ecx,512/32 ; count of dir entrys per sector = 16 adr_analyze: mov edi,[ebx+11] ; file attribute and edi,0xf cmp edi,0xf je adr_long_filename test edi,0x8 ; skip over volume label jne adr_long_filename ; Note: label can be same name as file/dir mov esi,[esp+0] ; filename need to be uppercase mov edi,ebx push ecx mov ecx,11 cld rep cmpsb ; compare 8+3 filename pop ecx je adr_found adr_long_filename: add ebx,32 ; position of next dir entry dec ecx jnz adr_analyze mov ecx,[longname_sec1] ; save 2 previous directory sectors mov [longname_sec1],eax ; for delete long filename mov [longname_sec2],ecx inc eax ; next sector dec edx jne adr_new_sector cmp [fat16_root],1 ; end of fat16 rootdir je adr_not_found adr_next_cluster: mov eax,[cluster_tmp] call get_FAT ; get next cluster cmp [hd_error],0 jne adr_not_found cmp eax,2 ; incorrect fat chain? jb adr_not_found ; yes cmp eax,[fatRESERVED] ; is it end of directory? jb adr_new_cluster ; no. analyse it adr_not_found: pop edi edi esi edx ecx ; first edi will remove ebx stc ; file not found ret adr_found: pop edi edi esi edx ecx ; first edi will remove ebx clc ; file found ret get_data_cluster: ;----------------------------------------------------------- ; input : EAX = cluster ; EBX = pointer to buffer ; EDX = # blocks to read in buffer ; ESI = # blocks to skip over ; output : if CARRY=0 ok EBX/EDX/ESI updated ; if CARRY=1 cluster out of range ; Note : if cluster=0 it's changed to read rootdir ;----------------------------------------------------------- push eax ecx mov [fat16_root],0 cmp eax,[LAST_CLUSTER] ja gdc_error ; too big cluster number, something is wrong cmp eax,2 jnb gdc_cluster mov eax,[ROOT_CLUSTER] ; if cluster < 2 then read rootdir cmp [fs_type],16 jne gdc_cluster mov eax,[ROOT_START] mov ecx,[ROOT_SECTORS] ; Note: not cluster size mov [fat16_root],1 ; flag for fat16 rootdir jmp gdc_read gdc_cluster: sub eax,2 mov ecx,[SECTORS_PER_CLUSTER] imul eax,ecx add eax,[DATA_START] gdc_read: test esi,esi ; first wanted block je gdcl1 ; yes, skip count is 0 dec esi jmp gdcl2 gdcl1: call hd_read cmp [hd_error],0 jne gdc_error add ebx,512 ; update pointer dec edx gdcl2: test edx,edx ; is all read? je out_of_read inc eax ; next sector dec ecx jnz gdc_read out_of_read: pop ecx eax clc ret gdc_error: pop ecx eax stc ret get_cluster_of_a_path: ;--------------------------------------------------------- ; input : EBX = pointer to a path string ; (example: the path "/files/data/document" become ; "files......data.......document...0" ; '.' = space char ; '0' = char(0) (ASCII=0) !!! ) ; output : if (CARRY=1) -> ERROR in the PATH ; if (CARRY=0) -> EAX=cluster ;--------------------------------------------------------- push ebx edx mov eax,[ROOT_CLUSTER] mov edx,ebx search_end_of_path: cmp byte [edx],0 je found_end_of_path inc edx ; '/' mov ebx,edx call analyze_directory jc directory_not_found mov eax,[ebx+20-2] ; read the HIGH 16bit cluster field mov ax,[ebx+26] ; read the LOW 16bit cluster field and eax,[fatMASK] add edx,11 ; 8+3 (name+extension) jmp search_end_of_path found_end_of_path: pop edx ebx clc ; no errors ret directory_not_found: pop edx ebx stc ; errors occour ret bcd2bin: ;---------------------------------- ; input : AL=BCD number (eg. 0x11) ; output : AH=0 ; AL=decimal number (eg. 11) ;---------------------------------- xor ah,ah shl ax,4 shr al,4 aad ret get_date_for_file: ;----------------------------------------------------- ; Get date from CMOS and pack day,month,year in AX ; DATE bits 0..4 : day of month 0..31 ; 5..8 : month of year 1..12 ; 9..15 : count of years from 1980 ;----------------------------------------------------- mov al,0x7 ;day out 0x70,al in al,0x71 call bcd2bin ror eax,5 mov al,0x8 ;month out 0x70,al in al,0x71 call bcd2bin ror eax,4 mov al,0x9 ;year out 0x70,al in al,0x71 call bcd2bin add ax,20 ;because CMOS return only the two last ;digit (eg. 2000 -> 00 , 2001 -> 01) and we rol eax,9 ;need the difference with 1980 (eg. 2001-1980) ret get_time_for_file: ;----------------------------------------------------- ; Get time from CMOS and pack hour,minute,second in AX ; TIME bits 0..4 : second (the low bit is lost) ; 5..10 : minute 0..59 ; 11..15 : hour 0..23 ;----------------------------------------------------- mov al,0x0 ;second out 0x70,al in al,0x71 call bcd2bin ror eax,6 mov al,0x2 ;minute out 0x70,al in al,0x71 call bcd2bin ror eax,6 mov al,0x4 ;hour out 0x70,al in al,0x71 call bcd2bin rol eax,11 ret set_current_time_for_entry: ;----------------------------------------------------- ; Set current time/date for file entry ; input : ebx = file entry pointer ;----------------------------------------------------- push eax call get_time_for_file ; update files date/time mov [ebx+22],ax call get_date_for_file mov [ebx+24],ax pop eax ret add_disk_free_space: ;----------------------------------------------------- ; input : ecx = cluster count ; Note : negative = remove clusters from free space ; positive = add clusters to free space ;----------------------------------------------------- test ecx,ecx ; no change je add_dfs_no cmp [fs_type],32 ; free disk space only used by fat32 jne add_dfs_no push eax ebx mov eax,[ADR_FSINFO] mov ebx,fsinfo_buffer call hd_read cmp [hd_error],0 jne add_not_fs cmp dword [ebx+0x1fc],0xaa550000 ; check sector id jne add_not_fs add [ebx+0x1e8],ecx push [fatStartScan] pop dword [ebx+0x1ec] call hd_write ; cmp [hd_error],0 ; jne add_not_fs add_not_fs: pop ebx eax add_dfs_no: ret file_read: ;-------------------------------------------------------------------------- ; INPUT : user-register register-in-this meaning symbol-in-this ; ; EAX EDI system call to write / ; EBX EAX (PAR0) pointer to file-name PAR0 ; EDX ECX (PAR1) pointer to buffer PAR1 ; ECX EBX (PAR2) vt file blocks to read PAR2 ; ESI EDX (PAR3) pointer to path PAR3 ; EDI ESI vt first 512 block to read ; EDI if 0 - read root ; ; output : eax = 0 - ok ; 3 - unknown FS ; 5 - file not found ; 6 - end of file ; 9 - fat table corrupted ; 10 - access denied ; ebx = size of file/directory ;-------------------------------------------------------------------------- cmp [fs_type], 16 jz fat_ok_for_reading cmp [fs_type], 32 jz fat_ok_for_reading xor ebx,ebx mov eax,ERROR_UNKNOWN_FS mov [hd1_status], ebx ret fat_ok_for_reading: ; call reserve_hd1 pushad mov ebx,edx call get_cluster_of_a_path jc file_to_read_not_found test edi,edi ; read rootdir jne no_read_root xor eax,eax call get_dir_size ; return rootdir size cmp [hd_error],0 jne file_access_denied mov [file_size],eax mov eax,[ROOT_CLUSTER] jmp file_read_start no_read_root: mov ebx,PUSHAD_EAX ; file name call analyze_directory jc file_to_read_not_found mov eax,[ebx+28] ; file size test byte [ebx+11],0x10 ; is it directory? jz read_set_size ; no mov eax,[ebx+20-2] ; FAT entry mov ax,[ebx+26] and eax,[fatMASK] call get_dir_size cmp [hd_error],0 jne file_access_denied read_set_size: mov [file_size],eax mov eax,[ebx+20-2] ; FAT entry mov ax,[ebx+26] and eax,[fatMASK] file_read_start: mov ebx,PUSHAD_ECX ; pointer to buffer mov edx,PUSHAD_EBX ; file blocks to read mov esi,PUSHAD_ESI ; first 512 block to read file_read_new_cluster: call get_data_cluster jc file_read_eof ; end of file or cluster out of range test edx,edx ; is all read? je file_read_OK ; yes call get_FAT ; get next cluster cmp [hd_error],0 jne file_access_denied cmp eax,[fatRESERVED] ; end of file jnb file_read_eof cmp eax,2 ; incorrect fat chain jnb file_read_new_cluster popad mov [hd1_status],0 mov ebx,[file_size] mov eax,ERROR_FAT_TABLE ret file_read_eof: cmp [hd_error],0 jne file_access_denied popad mov [hd1_status],0 mov ebx,[file_size] mov eax,ERROR_END_OF_FILE ret file_read_OK: popad mov [hd1_status],0 mov ebx,[file_size] xor eax,eax ret file_to_read_not_found: cmp [hd_error],0 jne file_access_denied popad mov [hd1_status],0 xor ebx,ebx mov eax,ERROR_FILE_NOT_FOUND ret file_access_denied: popad mov [hd1_status],0 xor ebx,ebx mov eax,ERROR_ACCESS_DENIED ret get_dir_size: ;----------------------------------------------------- ; input : eax = first cluster (0=rootdir) ; output : eax = directory size in bytes ;----------------------------------------------------- push edx xor edx,edx ; count of directory clusters test eax,eax jnz dir_size_next mov eax,[ROOT_SECTORS] shl eax,9 ; fat16 rootdir size in bytes cmp [fs_type],16 je dir_size_ret mov eax,[ROOT_CLUSTER] dir_size_next: cmp eax,2 ; incorrect fat chain jb dir_size_end cmp eax,[fatRESERVED] ; end of directory ja dir_size_end call get_FAT ; get next cluster cmp [hd_error],0 jne dir_size_ret inc edx jmp dir_size_next dir_size_end: imul eax,[SECTORS_PER_CLUSTER],512 ; cluster size in bytes imul eax,edx dir_size_ret: pop edx ret 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 get_hd_info: ;----------------------------------------------------------- ; output : eax = 0 - ok ; 3 - unknown FS ; 10 - access denied ; edx = cluster size in bytes ; ebx = total clusters on disk ; ecx = free clusters on disk ;----------------------------------------------------------- cmp [fs_type], 16 jz info_fat_ok cmp [fs_type], 32 jz info_fat_ok xor edx,edx xor ebx,ebx xor ecx,ecx mov eax,ERROR_UNKNOWN_FS ret info_fat_ok: ; call reserve_hd1 xor ecx,ecx ; count of free clusters mov eax,2 mov ebx,[LAST_CLUSTER] info_cluster: push eax call get_FAT ; get cluster info cmp [hd_error],0 jne info_access_denied test eax,eax ; is it free? jnz info_used ; no inc ecx info_used: pop eax inc eax cmp eax,ebx ; is above last cluster? jbe info_cluster ; no. test next cluster dec ebx ; cluster count imul edx,[SECTORS_PER_CLUSTER],512 ; cluster size in bytes mov [hd1_status],0 xor eax,eax ret info_access_denied: add esp,4 xor edx,edx xor ebx,ebx xor ecx,ecx mov eax,ERROR_ACCESS_DENIED ret update_disk: ;----------------------------------------------------------- ; write changed fat and cache to disk ;----------------------------------------------------------- cmp [fat_change],0 ; is fat changed? je upd_no_change call write_fat_sector cmp [hd_error],0 jne update_disk_acces_denied upd_no_change: call write_cache update_disk_acces_denied: ret ; \begin{diamond} hd_find_lfn: ; in: esi+ebp -> name ; out: CF=1 - file not found ; else CF=0 and edi->direntry, eax=sector ; destroys eax push esi edi push 0 push 0 push fat16_root_first push fat16_root_next mov eax, [ROOT_CLUSTER] cmp [fs_type], 32 jz .fat32 .loop: call fat_find_lfn jc .notfound cmp byte [esi], 0 jz .found .continue: 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: test ebp, ebp jz @f mov esi, ebp xor ebp, ebp jmp .continue @@: lea eax, [esp+8] cmp dword [eax], 0 jz .root call fat_get_sector jmp .cmn .root: mov eax, [eax+4] add eax, [ROOT_START] .cmn: add esp, 20 ; CF=0 pop esi ret ;---------------------------------------------------------------- ; ; fs_HdRead - LFN variant for reading hard disk ; ; esi points to filename ; ebx pointer to 64-bit number = first wanted byte, 0+ ; may be ebx=0 - start from first byte ; ecx number of bytes to read, 0+ ; edx mem location to return data ; ; ret ebx = bytes read or 0xffffffff file not found ; eax = 0 ok read or other = errormsg ; ;-------------------------------------------------------------- fs_HdRead: cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f cmp [fs_type], 1 jz ntfs_HdRead or ebx, -1 mov eax, ERROR_UNKNOWN_FS ret @@: push edi cmp byte [esi], 0 jnz @f .noaccess: pop edi .noaccess_2: or ebx, -1 mov eax, ERROR_ACCESS_DENIED ret @@: 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 pop ebx cmp [hd_error],0 jne .noaccess_1 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 mov eax, ebx pop ebx cmp [hd_error],0 jne .noaccess_3 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_1 jmp .new_cluster .noaccess_3: pop eax .noaccess_1: pop eax push 11 .done: mov ebx, edx pop eax edx ecx edi sub ebx, edx ret .eof: mov ebx, edx pop eax edx ecx sub ebx, edx jmp .reteof ;---------------------------------------------------------------- ; ; fs_HdReadFolder - LFN variant for reading hard disk folder ; ; esi points to filename ; ebx pointer to structure 32-bit number = first wanted block, 0+ ; & flags (bitfields) ; flags: bit 0: 0=ANSI names, 1=UNICODE names ; ecx number of blocks to read, 0+ ; edx mem location to return data ; ; ret ebx = blocks read or 0xffffffff folder not found ; eax = 0 ok read or other = errormsg ; ;-------------------------------------------------------------- fs_HdReadFolder: cmp [fs_type], 1 jz ntfs_HdReadFolder cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f push ERROR_UNSUPPORTED_FS pop eax or ebx, -1 ret @@: mov eax, [ROOT_CLUSTER] push edi cmp byte [esi], 0 jz .doit call hd_find_lfn jnc .found pop edi or ebx, -1 mov eax, ERROR_FILE_NOT_FOUND ret .found: test byte [edi+11], 0x10 ; do not allow read files jnz .found_dir pop edi or ebx, -1 mov eax, ERROR_ACCESS_DENIED ret .found_dir: mov eax, [edi+20-2] mov ax, [edi+26] ; eax=cluster .doit: push esi ecx push ebp sub esp, 262*2 ; reserve space for LFN mov ebp, esp push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE name mov ebx, [ebx] ; init header push eax ecx mov edi, edx mov ecx, 32/4 xor eax, eax rep stosd pop ecx eax mov byte [edx], 1 ; version mov esi, edi ; esi points to BDFE .new_cluster: mov [cluster_tmp], eax test eax, eax jnz @f cmp [fs_type], 32 jz .notfound mov eax, [ROOT_START] push [ROOT_SECTORS] push ebx jmp .new_sector @@: dec eax dec eax imul eax, [SECTORS_PER_CLUSTER] push [SECTORS_PER_CLUSTER] add eax, [DATA_START] push ebx .new_sector: mov ebx, buffer mov edi, ebx call hd_read cmp [hd_error], 0 jnz .notfound2 add ebx, 512 push eax .l1: call fat_get_name jc .l2 cmp byte [edi+11], 0xF jnz .do_bdfe add edi, 0x20 cmp edi, ebx jb .do_bdfe pop eax inc eax dec dword [esp+4] jnz @f mov eax, [cluster_tmp] test eax, eax jz .done call get_FAT cmp [hd_error], 0 jnz .notfound2 cmp eax, 2 jb .done cmp eax, [fatRESERVED] jae .done push eax mov eax, [SECTORS_PER_CLUSTER] mov [esp+8], eax pop eax mov [cluster_tmp], eax dec eax dec eax imul eax, [SECTORS_PER_CLUSTER] add eax, [DATA_START] @@: mov ebx, buffer mov edi, ebx call hd_read cmp [hd_error], 0 jnz .notfound2 add ebx, 512 push eax .do_bdfe: inc dword [edx+8] ; new file found dec dword [esp+4] jns .l2 dec ecx js .l2 inc dword [edx+4] ; new file block copied call fat_entry_to_bdfe .l2: add edi, 0x20 cmp edi, ebx jb .l1 pop eax inc eax dec dword [esp+4] jnz .new_sector mov eax, [cluster_tmp] test eax, eax jz .done call get_FAT cmp [hd_error], 0 jnz .notfound2 cmp eax, 2 jb .done cmp eax, [fatRESERVED] jae .done push eax mov eax, [SECTORS_PER_CLUSTER] mov [esp+8], eax pop eax pop ebx add esp, 4 jmp .new_cluster .notfound2: add esp, 8 .notfound: add esp, 262*2+4 pop ebp ecx esi edi mov eax, ERROR_FILE_NOT_FOUND or ebx, -1 ret .done: add esp, 262*2+4+8 pop ebp mov ebx, [edx+4] xor eax, eax dec ecx js @f mov al, ERROR_END_OF_FILE @@: pop ecx esi edi ret fat16_root_next: cmp edi, buffer+0x200-0x20 jae fat16_root_next_sector add edi, 0x20 ret ; CF=0 fat16_root_next_sector: ; read next sector push [longname_sec2] pop [longname_sec1] push ecx mov ecx, [eax+4] push ecx add ecx, [ROOT_START] mov [longname_sec2], ecx pop ecx inc ecx mov [eax+4], ecx cmp ecx, [ROOT_SECTORS] pop ecx jae fat16_root_first.readerr fat16_root_first: mov eax, [eax+4] add eax, [ROOT_START] push ebx mov edi, buffer mov ebx, edi call hd_read pop ebx cmp [hd_error], 0 jnz .readerr ret ; CF=0 .readerr: stc ret fat16_root_begin_write: push edi eax call fat16_root_first pop eax edi ret fat16_root_end_write: pusha mov eax, [eax+4] add eax, [ROOT_START] mov ebx, buffer call hd_write popa ret fat16_root_next_write: cmp edi, buffer+0x200 jae @f ret @@: call fat16_root_end_write jmp fat16_root_next_sector fat16_root_extend_dir: stc ret fat_notroot_next: cmp edi, buffer+0x200-0x20 jae fat_notroot_next_sector add edi, 0x20 ret ; CF=0 fat_notroot_next_sector: push [longname_sec2] pop [longname_sec1] push eax call fat_get_sector mov [longname_sec2], eax pop eax push ecx mov ecx, [eax+4] inc ecx cmp ecx, [SECTORS_PER_CLUSTER] jae fat_notroot_next_cluster mov [eax+4], ecx jmp @f fat_notroot_next_cluster: push eax mov eax, [eax] call get_FAT mov ecx, eax pop eax cmp [hd_error], 0 jnz fat_notroot_next_err cmp ecx, [fatRESERVED] jae fat_notroot_next_err mov [eax], ecx and dword [eax+4], 0 @@: pop ecx fat_notroot_first: call fat_get_sector push ebx mov edi, buffer mov ebx, edi call hd_read pop ebx cmp [hd_error], 0 jnz @f ret ; CF=0 fat_notroot_next_err: pop ecx @@: stc ret fat_notroot_begin_write: push eax edi call fat_notroot_first pop edi eax ret fat_notroot_end_write: call fat_get_sector push ebx mov ebx, buffer call hd_write pop ebx ret fat_notroot_next_write: cmp edi, buffer+0x200 jae @f ret @@: push eax call fat_notroot_end_write pop eax jmp fat_notroot_next_sector fat_notroot_extend_dir: push eax call get_free_FAT jnc .found pop eax ret ; CF=1 .found: push edx mov edx, [fatEND] call set_FAT mov edx, eax mov eax, [esp+4] mov eax, [eax] push edx call set_FAT pop edx cmp [hd_error], 0 jz @f pop edx pop eax stc ret @@: push ecx or ecx, -1 call add_disk_free_space ; zero new cluster mov ecx, 512/4 mov edi, buffer push edi xor eax, eax rep stosd pop edi pop ecx mov eax, [esp+4] mov [eax], edx and dword [eax+4], 0 pop edx mov eax, [eax] dec eax dec eax push ebx ecx mov ecx, [SECTORS_PER_CLUSTER] imul eax, ecx add eax, [DATA_START] mov ebx, edi @@: call hd_write inc eax loop @b pop ecx ebx eax clc ret fat_get_sector: push ecx mov ecx, [eax] dec ecx dec ecx imul ecx, [SECTORS_PER_CLUSTER] add ecx, [DATA_START] add ecx, [eax+4] mov eax, ecx pop ecx ret ;---------------------------------------------------------------- ; ; fs_HdRewrite - LFN variant for writing hard disk ; ; esi points to filename ; ebx ignored (reserved) ; ecx number of bytes to write, 0+ ; edx mem location to data ; ; ret ebx = number of written bytes ; eax = 0 ok read or other = errormsg ; ;-------------------------------------------------------------- fshrad: mov eax, ERROR_ACCESS_DENIED xor ebx, ebx ret fshrfs: mov eax, ERROR_UNKNOWN_FS xor ebx, ebx ret fs_HdCreateFolder: mov al, 1 jmp fs_HdRewrite.common fs_HdRewrite: xor eax, eax .common: cmp [fs_type], 1 jz ntfs_HdRewrite cmp [fs_type], 16 jz @f cmp [fs_type], 32 jnz fshrfs @@: cmp byte [esi], 0 jz fshrad pushad xor edi, edi push esi test ebp, ebp jz @f mov esi, ebp @@: lodsb test al, al jz @f cmp al, '/' jnz @b lea edi, [esi-1] jmp @b @@: pop esi test edi, edi jnz .noroot test ebp, ebp jnz .hasebp mov ebp, [ROOT_CLUSTER] cmp [fs_type], 32 jz .pushnotroot push fat16_root_extend_dir push fat16_root_end_write push fat16_root_next_write push fat16_root_begin_write xor ebp, ebp push ebp push ebp push fat16_root_first push fat16_root_next jmp .common1 .hasebp: mov eax, ERROR_ACCESS_DENIED cmp byte [ebp], 0 jz .ret1 push ebp xor ebp, ebp call hd_find_lfn pop esi jc .notfound0 jmp .common0 .noroot: mov eax, ERROR_ACCESS_DENIED cmp byte [edi+1], 0 jz .ret1 ; check existence mov byte [edi], 0 push edi call hd_find_lfn pop esi mov byte [esi], '/' jnc @f .notfound0: mov eax, ERROR_FILE_NOT_FOUND .ret1: mov [esp+28], eax popad xor ebx, ebx ret @@: inc esi .common0: test byte [edi+11], 0x10 ; must be directory mov eax, ERROR_ACCESS_DENIED jz .ret1 mov ebp, [edi+20-2] mov bp, [edi+26] ; ebp=cluster mov eax, ERROR_FAT_TABLE cmp ebp, 2 jb .ret1 .pushnotroot: push fat_notroot_extend_dir push fat_notroot_end_write push fat_notroot_next_write push fat_notroot_begin_write push 0 push ebp push fat_notroot_first push fat_notroot_next .common1: call fat_find_lfn jc .notfound ; found test byte [edi+11], 10h jz .exists_file ; found directory; if we are creating directory, return OK, ; if we are creating file, say "access denied" add esp, 32 popad test al, al mov eax, ERROR_ACCESS_DENIED jz @f mov al, 0 @@: xor ebx, ebx ret .exists_file: ; found file; if we are creating directory, return "access denied", ; if we are creating file, delete existing file and continue cmp byte [esp+32+28], 0 jz @f add esp, 32 popad mov eax, ERROR_ACCESS_DENIED xor ebx, ebx ret @@: ; delete FAT chain push edi xor eax, eax mov dword [edi+28], eax ; zero size xor ecx, ecx mov eax, [edi+20-2] mov ax, [edi+26] mov word [edi+20], cx mov word [edi+26], cx test eax, eax jz .done1 @@: cmp eax, [fatRESERVED] jae .done1 push edx xor edx, edx call set_FAT mov eax, edx pop edx inc ecx jmp @b .done1: pop edi call get_time_for_file mov [edi+22], ax call get_date_for_file mov [edi+24], ax mov [edi+18], ax or byte [edi+11], 20h ; set 'archive' attribute jmp .doit .notfound: ; file is not found; generate short name call fat_name_is_legal jc @f add esp, 32 popad mov eax, ERROR_FILE_NOT_FOUND xor ebx, ebx ret @@: sub esp, 12 mov edi, esp call fat_gen_short_name .test_short_name_loop: push esi edi ecx mov esi, edi lea eax, [esp+12+12+8] mov [eax], ebp and dword [eax+4], 0 call dword [eax-4] jc .found .test_short_name_entry: cmp byte [edi+11], 0xF jz .test_short_name_cont mov ecx, 11 push esi edi repz cmpsb pop edi esi jz .short_name_found .test_short_name_cont: lea eax, [esp+12+12+8] call dword [eax-8] jnc .test_short_name_entry jmp .found .short_name_found: pop ecx edi esi call fat_next_short_name jnc .test_short_name_loop .disk_full: add esp, 12+32 popa mov eax, ERROR_DISK_FULL xor ebx, ebx ret .found: pop ecx edi esi ; now find space in directory ; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~' mov al, '~' push ecx edi mov ecx, 8 repnz scasb push 1 pop eax ; 1 entry jnz .notilde ; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total xor eax, eax @@: cmp byte [esi], 0 jz @f inc esi inc eax jmp @b @@: sub esi, eax add eax, 12+13 mov ecx, 13 push edx cdq div ecx pop edx .notilde: push -1 push -1 push -1 ; find <eax> successive entries in directory xor ecx, ecx push eax lea eax, [esp+16+8+12+8] mov [eax], ebp and dword [eax+4], 0 call dword [eax-4] pop eax jnc .scan_dir .fsfrfe3: add esp, 12+8+12+32 popad mov eax, 11 xor ebx, ebx ret .scan_dir: cmp byte [edi], 0 jz .free cmp byte [edi], 0xE5 jz .free xor ecx, ecx .scan_cont: push eax lea eax, [esp+16+8+12+8] call dword [eax-8] pop eax jnc .scan_dir cmp [hd_error], 0 jnz .fsfrfe3 push eax lea eax, [esp+16+8+12+8] call dword [eax+20] ; extend directory pop eax jnc .scan_dir add esp, 12+8+12+32 popad mov eax, ERROR_DISK_FULL xor ebx, ebx ret .free: test ecx, ecx jnz @f mov [esp], edi mov ecx, [esp+12+8+12+8] mov [esp+4], ecx mov ecx, [esp+12+8+12+12] mov [esp+8], ecx xor ecx, ecx @@: inc ecx cmp ecx, eax jb .scan_cont ; found! ; calculate name checksum push esi ecx mov esi, [esp+8+12] mov ecx, 11 xor eax, eax @@: ror al, 1 add al, [esi] inc esi loop @b pop ecx esi pop edi pop dword [esp+8+12+12] pop dword [esp+8+12+12] ; edi points to first entry in free chunk dec ecx jz .nolfn push esi push eax lea eax, [esp+8+8+12+8] call dword [eax+8] ; begin write mov al, 40h .writelfn: or al, cl mov esi, [esp+4] push ecx dec ecx imul ecx, 13 add esi, ecx stosb mov cl, 5 call fs_RamdiskRewrite.read_symbols mov ax, 0xF stosw mov al, [esp+4] stosb mov cl, 6 call fs_RamdiskRewrite.read_symbols xor eax, eax stosw mov cl, 2 call fs_RamdiskRewrite.read_symbols pop ecx lea eax, [esp+8+8+12+8] call dword [eax+12] ; next write xor eax, eax loop .writelfn pop eax pop esi ; lea eax, [esp+8+12+8] ; call dword [eax+16] ; end write .nolfn: xchg esi, [esp] mov ecx, 11 rep movsb mov word [edi], 20h ; attributes sub edi, 11 pop esi ecx add esp, 12 mov byte [edi+13], 0 ; tenths of a second at file creation time call get_time_for_file mov [edi+14], ax ; creation time mov [edi+22], ax ; last write time call get_date_for_file mov [edi+16], ax ; creation date mov [edi+24], ax ; last write date mov [edi+18], ax ; last access date xor ecx, ecx mov word [edi+20], cx ; high word of cluster mov word [edi+26], cx ; low word of cluster - to be filled mov dword [edi+28], ecx ; file size - to be filled cmp byte [esp+32+28], cl jz .doit ; create directory mov byte [edi+11], 10h ; attributes: folder mov edx, edi lea eax, [esp+8] call dword [eax+16] ; flush directory push ecx mov ecx, [SECTORS_PER_CLUSTER] shl ecx, 9 jmp .doit2 .doit: lea eax, [esp+8] call dword [eax+16] ; flush directory push ecx mov ecx, [esp+4+32+24] .doit2: push ecx push edi mov esi, edx test ecx, ecx jz .done call get_free_FAT jc .diskfull push eax mov [edi+26], ax shr eax, 16 mov [edi+20], ax lea eax, [esp+16+8] call dword [eax+16] ; flush directory pop eax push edx mov edx, [fatEND] call set_FAT pop edx .write_cluster: push eax dec eax dec eax mov ebp, [SECTORS_PER_CLUSTER] imul eax, ebp add eax, [DATA_START] ; write data .write_sector: cmp byte [esp+16+32+28], 0 jnz .writedir mov ecx, 512 cmp dword [esp+8], ecx jb .writeshort ; we can write directly from given buffer mov ebx, esi add esi, ecx jmp .writecommon .writeshort: mov ecx, [esp+8] push ecx mov edi, buffer mov ebx, edi rep movsb .writedircont: mov ecx, buffer+0x200 sub ecx, edi push eax xor eax, eax rep stosb pop eax pop ecx .writecommon: call hd_write cmp [hd_error], 0 jnz .writeerr inc eax sub dword [esp+8], ecx jz .writedone dec ebp jnz .write_sector ; allocate new cluster pop eax mov ecx, eax call get_free_FAT jc .diskfull push edx mov edx, [fatEND] call set_FAT xchg eax, ecx mov edx, ecx call set_FAT pop edx xchg eax, ecx jmp .write_cluster .diskfull: mov eax, ERROR_DISK_FULL jmp .ret .writeerr: pop eax sub esi, ecx mov eax, 11 jmp .ret .writedone: pop eax .done: xor eax, eax .ret: pop edi ecx mov ebx, esi sub ebx, edx pop ebp mov [esp+32+28], eax lea eax, [esp+8] call dword [eax+8] mov [edi+28], ebx call dword [eax+16] mov [esp+32+16], ebx lea eax, [ebx+511] shr eax, 9 mov ecx, [SECTORS_PER_CLUSTER] lea eax, [eax+ecx-1] xor edx, edx div ecx mov ecx, ebp sub ecx, eax call add_disk_free_space add esp, 32 call update_disk popad ret .writedir: push 512 mov edi, buffer mov ebx, edi mov ecx, [SECTORS_PER_CLUSTER] shl ecx, 9 cmp ecx, [esp+12] jnz .writedircont dec dword [esp+16] push esi mov ecx, 32/4 rep movsd pop esi mov dword [edi-32], '. ' mov dword [edi-32+4], ' ' mov dword [edi-32+8], ' ' mov byte [edi-32+11], 10h push esi mov ecx, 32/4 rep movsd pop esi mov dword [edi-32], '.. ' mov dword [edi-32+4], ' ' mov dword [edi-32+8], ' ' mov byte [edi-32+11], 10h mov ecx, [esp+20+8] cmp ecx, [ROOT_CLUSTER] jnz @f xor ecx, ecx @@: mov word [edi-32+26], cx shr ecx, 16 mov [edi-32+20], cx jmp .writedircont ;---------------------------------------------------------------- ; ; fs_HdWrite - LFN variant for writing to hard disk ; ; esi points to filename ; ebx pointer to 64-bit number = first wanted byte, 0+ ; may be ebx=0 - start from first byte ; ecx number of bytes to write, 0+ ; edx mem location to data ; ; ret ebx = bytes written (maybe 0) ; eax = 0 ok write or other = errormsg ; ;-------------------------------------------------------------- fs_HdWrite.access_denied: push ERROR_ACCESS_DENIED fs_HdWrite.ret0: pop eax xor ebx, ebx ret fs_HdWrite.ret11: push 11 jmp fs_HdWrite.ret0 fs_HdWrite: cmp [fs_type], 1 jz ntfs_HdWrite cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f push ERROR_UNKNOWN_FS jmp .ret0 @@: cmp byte [esi], 0 jz .access_denied pushad call hd_find_lfn pushfd cmp [hd_error], 0 jz @f popfd popad push 11 jmp .ret0 @@: popfd jnc .found popad push ERROR_FILE_NOT_FOUND jmp .ret0 .found: ; FAT does not support files larger than 4GB test ebx, ebx jz .l1 cmp dword [ebx+4], 0 jz @f .eof: popad push ERROR_END_OF_FILE jmp .ret0 @@: mov ebx, [ebx] .l1: ; now edi points to direntry, ebx=start byte to write, ; ecx=number of bytes to write, edx=data pointer ; extend file if needed add ecx, ebx jc .eof ; FAT does not support files larger than 4GB push eax ; save directory sector push 0 ; return value=0 call get_time_for_file mov [edi+22], ax ; last write time call get_date_for_file mov [edi+24], ax ; last write date mov [edi+18], ax ; last access date push dword [edi+28] ; save current file size cmp ecx, [edi+28] jbe .length_ok cmp ecx, ebx jz .length_ok call hd_extend_file jnc .length_ok mov [esp+4], eax ; hd_extend_file can return three error codes: FAT table error, device error or disk full. ; First two cases are fatal errors, in third case we may write some data cmp al, ERROR_DISK_FULL jz .disk_full pop eax pop eax mov [esp+4+28], eax pop eax popad xor ebx, ebx ret .disk_full: ; correct number of bytes to write mov ecx, [edi+28] cmp ecx, ebx ja .length_ok .ret: call update_disk cmp [hd_error], 0 jz @f mov byte [esp+4], 11 @@: pop eax pop eax mov [esp+4+28], eax ; eax=return value pop eax sub edx, [esp+20] mov [esp+16], edx ; ebx=number of written bytes popad ret .length_ok: mov esi, [edi+28] mov eax, [edi+20-2] mov ax, [edi+26] mov edi, eax ; edi=current cluster xor ebp, ebp ; ebp=current sector in cluster ; save directory mov eax, [esp+8] push ebx mov ebx, buffer call hd_write pop ebx cmp [hd_error], 0 jz @f .device_err: mov byte [esp+4], 11 jmp .ret @@: ; now ebx=start pos, ecx=end pos, both lie inside file sub ecx, ebx jz .ret .write_loop: ; skip unmodified sectors cmp dword [esp], 0x200 jb .modify sub ebx, 0x200 jae .skip add ebx, 0x200 .modify: ; get length of data in current sector push ecx sub ebx, 0x200 jb .hasdata neg ebx xor ecx, ecx jmp @f .hasdata: neg ebx cmp ecx, ebx jbe @f mov ecx, ebx @@: ; get current sector number mov eax, edi dec eax dec eax imul eax, [SECTORS_PER_CLUSTER] add eax, [DATA_START] add eax, ebp ; load sector if needed cmp dword [esp+4], 0 ; we don't need to read uninitialized data jz .noread cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten jz .noread cmp ecx, esi ; (same for the last sector) jz .noread push ebx mov ebx, buffer call hd_read pop ebx cmp [hd_error], 0 jz @f .device_err2: pop ecx jmp .device_err @@: .noread: ; zero uninitialized data if file was extended (because hd_extend_file does not this) push eax ecx edi xor eax, eax mov ecx, 0x200 sub ecx, [esp+4+12] jbe @f mov edi, buffer add edi, [esp+4+12] rep stosb @@: ; zero uninitialized data in the last sector mov ecx, 0x200 sub ecx, esi jbe @f mov edi, buffer add edi, esi rep stosb @@: pop edi ecx ; copy new data mov eax, edx neg ebx jecxz @f add ebx, buffer+0x200 call memmove xor ebx, ebx @@: pop eax ; save sector push ebx mov ebx, buffer call hd_write pop ebx cmp [hd_error], 0 jnz .device_err2 add edx, ecx sub [esp], ecx pop ecx jz .ret .skip: ; next sector inc ebp cmp ebp, [SECTORS_PER_CLUSTER] jb @f xor ebp, ebp mov eax, edi call get_FAT mov edi, eax cmp [hd_error], 0 jnz .device_err @@: sub esi, 0x200 jae @f xor esi, esi @@: sub dword [esp], 0x200 jae @f and dword [esp], 0 @@: jmp .write_loop hd_extend_file.zero_size: xor eax, eax jmp hd_extend_file.start_extend ; extends file on hd to given size (new data area is undefined) ; in: edi->direntry, ecx=new size ; out: CF=0 => OK, eax=0 ; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL or 11) hd_extend_file: push ebp mov ebp, [SECTORS_PER_CLUSTER] imul ebp, [BYTES_PER_SECTOR] push ecx ; find the last cluster of file mov eax, [edi+20-2] mov ax, [edi+26] mov ecx, [edi+28] jecxz .zero_size .last_loop: sub ecx, ebp jbe .last_found call get_FAT cmp [hd_error], 0 jz @f .device_err: pop ecx .device_err2: pop ebp push 11 .ret_err: pop eax stc ret @@: cmp eax, 2 jb .fat_err cmp eax, [fatRESERVED] jb .last_loop .fat_err: pop ecx ebp push ERROR_FAT_TABLE jmp .ret_err .last_found: push eax call get_FAT cmp [hd_error], 0 jz @f pop eax jmp .device_err @@: cmp eax, [fatRESERVED] pop eax jb .fat_err ; set length to full number of clusters sub [edi+28], ecx .start_extend: pop ecx ; now do extend push edx mov edx, 2 ; start scan from cluster 2 .extend_loop: cmp [edi+28], ecx jae .extend_done ; add new cluster push eax call get_free_FAT jc .disk_full mov edx, [fatEND] call set_FAT mov edx, eax pop eax test eax, eax jz .first_cluster push edx call set_FAT pop edx jmp @f .first_cluster: ror edx, 16 mov [edi+20], dx ror edx, 16 mov [edi+26], dx @@: push ecx mov ecx, -1 call add_disk_free_space pop ecx mov eax, edx cmp [hd_error], 0 jnz .device_err3 add [edi+28], ebp jmp .extend_loop .extend_done: mov [edi+28], ecx pop edx ebp xor eax, eax ; CF=0 ret .device_err3: pop edx jmp .device_err2 .disk_full: pop eax edx ebp push ERROR_DISK_FULL pop eax cmp [hd_error], 0 jz @f mov al, 11 @@: stc ret ;---------------------------------------------------------------- ; ; fs_HdSetFileEnd - set end of file on hard disk ; ; esi points to filename ; ebx points to 64-bit number = new file size ; ecx ignored (reserved) ; edx ignored (reserved) ; ; ret eax = 0 ok or other = errormsg ; ;-------------------------------------------------------------- fs_HdSetFileEnd: cmp [fs_type], 1 jz ntfs_HdSetFileEnd cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f push ERROR_UNKNOWN_FS .ret: pop eax ret @@: cmp byte [esi], 0 jnz @f .access_denied: push ERROR_ACCESS_DENIED jmp .ret @@: push edi call hd_find_lfn pushfd cmp [hd_error], 0 jz @f popfd push 11 jmp .ret @@: popfd jnc @f pop edi push ERROR_FILE_NOT_FOUND jmp .ret @@: ; must not be directory test byte [edi+11], 10h jz @f pop edi jmp .access_denied @@: ; file size must not exceed 4 Gb cmp dword [ebx+4], 0 jz @f pop edi push ERROR_END_OF_FILE jmp .ret @@: push eax ; save directory sector ; set file modification date/time to current call fat_update_datetime mov eax, [ebx] cmp eax, [edi+28] jb .truncate ja .expand pop eax mov ebx, buffer call hd_write pop edi xor eax, eax cmp [hd_error], 0 jz @f mov al, 11 @@: ret .expand: push ebx ebp ecx push dword [edi+28] ; save old size mov ecx, eax call hd_extend_file push eax ; return code jnc .expand_ok cmp al, ERROR_DISK_FULL jz .disk_full .pop_ret: call update_disk pop eax ecx ebp ebx ecx edi edi ret .expand_ok: .disk_full: ; save directory mov eax, [edi+28] xchg eax, [esp+20] mov ebx, buffer call hd_write mov eax, [edi+20-2] mov ax, [edi+26] mov edi, eax cmp [hd_error], 0 jz @f .pop_ret11: mov byte [esp], 11 jmp .pop_ret @@: ; now zero new data xor ebp, ebp ; edi=current cluster, ebp=sector in cluster ; [esp+20]=new size, [esp+4]=old size, [esp]=return code .zero_loop: sub dword [esp+4], 0x200 jae .next_cluster lea eax, [edi-2] imul eax, [SECTORS_PER_CLUSTER] add eax, [DATA_START] add eax, ebp cmp dword [esp+4], -0x200 jz .noread mov ebx, buffer call hd_read cmp [hd_error], 0 jnz .err_next .noread: mov ecx, [esp+4] neg ecx push edi mov edi, buffer+0x200 add edi, [esp+8] push eax xor eax, eax mov [esp+12], eax rep stosb pop eax pop edi call hd_write cmp [hd_error], 0 jz .next_cluster .err_next: mov byte [esp], 11 .next_cluster: sub dword [esp+20], 0x200 jbe .pop_ret inc ebp cmp ebp, [SECTORS_PER_CLUSTER] jb .zero_loop xor ebp, ebp mov eax, edi call get_FAT mov edi, eax cmp [hd_error], 0 jnz .pop_ret11 jmp .zero_loop .truncate: mov [edi+28], eax push ecx mov ecx, [edi+20-2] mov cx, [edi+26] push eax test eax, eax jz .zero_size ; find new last cluster @@: mov eax, [SECTORS_PER_CLUSTER] shl eax, 9 sub [esp], eax jbe @f mov eax, ecx call get_FAT mov ecx, eax cmp [hd_error], 0 jz @b .device_err3: pop eax ecx eax edi push 11 pop eax ret @@: ; we will zero data at the end of last sector - remember it push ecx ; terminate FAT chain push edx mov eax, ecx mov edx, [fatEND] call set_FAT mov eax, edx pop edx cmp [hd_error], 0 jz @f .device_err4: pop ecx jmp .device_err3 .zero_size: and word [edi+20], 0 and word [edi+26], 0 push 0 mov eax, ecx @@: ; delete FAT chain call clear_cluster_chain cmp [hd_error], 0 jnz .device_err4 ; save directory mov eax, [esp+12] push ebx mov ebx, buffer call hd_write pop ebx cmp [hd_error], 0 jnz .device_err4 ; zero last sector, ignore errors pop ecx pop eax dec ecx imul ecx, [SECTORS_PER_CLUSTER] add ecx, [DATA_START] push eax sar eax, 9 add ecx, eax pop eax and eax, 0x1FF jz .truncate_done push ebx eax mov eax, ecx mov ebx, buffer call hd_read pop eax lea edi, [buffer+eax] push ecx mov ecx, 0x200 sub ecx, eax xor eax, eax rep stosb pop eax call hd_write pop ebx .truncate_done: pop ecx eax edi call update_disk xor eax, eax cmp [hd_error], 0 jz @f mov al, 11 @@: ret fs_HdGetFileInfo: cmp [fs_type], 1 jz ntfs_HdGetFileInfo cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f mov eax, ERROR_UNKNOWN_FS ret @@: cmp byte [esi], 0 jnz @f mov eax, 2 ret @@: push edi call hd_find_lfn pushfd cmp [hd_error], 0 jz @f popfd pop edi mov eax, 11 ret @@: popfd jmp fs_GetFileInfo_finish fs_HdSetFileInfo: cmp [fs_type], 1 jz ntfs_HdSetFileInfo cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f mov eax, ERROR_UNKNOWN_FS ret @@: cmp byte [esi], 0 jnz @f mov eax, 2 ret @@: push edi call hd_find_lfn pushfd cmp [hd_error], 0 jz @f popfd pop edi mov eax, 11 ret @@: popfd jnc @f pop edi mov eax, ERROR_FILE_NOT_FOUND ret @@: push eax call bdfe_to_fat_entry pop eax mov ebx, buffer call hd_write call update_disk pop edi xor eax, eax ret ;---------------------------------------------------------------- ; ; fs_HdDelete - delete file or empty folder from hard disk ; ; esi points to filename ; ; ret eax = 0 ok or other = errormsg ; ;-------------------------------------------------------------- fs_HdDelete: cmp [fs_type], 1 jz ntfs_HdDelete cmp [fs_type], 16 jz @f cmp [fs_type], 32 jz @f push ERROR_UNKNOWN_FS .pop_ret: pop eax ret @@: cmp byte [esi], 0 jnz @f ; cannot delete root! .access_denied: push ERROR_ACCESS_DENIED jmp .pop_ret @@: and [longname_sec1], 0 and [longname_sec2], 0 push edi call hd_find_lfn jnc .found pop edi push ERROR_FILE_NOT_FOUND jmp .pop_ret .found: cmp dword [edi], '. ' jz .access_denied2 cmp dword [edi], '.. ' jz .access_denied2 test byte [edi+11], 10h jz .dodel ; we can delete only empty folders! pushad mov ebp, [edi+20-2] mov bp, [edi+26] xor ecx, ecx lea eax, [ebp-2] imul eax, [SECTORS_PER_CLUSTER] add eax, [DATA_START] mov ebx, buffer call hd_read cmp [hd_error], 0 jnz .err1 add ebx, 2*0x20 .checkempty: cmp byte [ebx], 0 jz .empty cmp byte [ebx], 0xE5 jnz .notempty add ebx, 0x20 cmp ebx, buffer+0x200 jb .checkempty inc ecx cmp ecx, [SECTORS_PER_CLUSTER] jb @f mov eax, ebp call get_FAT cmp [hd_error], 0 jnz .err1 mov ebp, eax xor ecx, ecx @@: lea eax, [ebp-2] imul eax, [SECTORS_PER_CLUSTER] add eax, [DATA_START] add eax, ecx mov ebx, buffer call hd_read cmp [hd_error], 0 jz .checkempty .err1: popad .err2: pop edi push 11 pop eax ret .notempty: popad .access_denied2: pop edi push ERROR_ACCESS_DENIED pop eax ret .empty: popad push ebx mov ebx, buffer call hd_read pop ebx cmp [hd_error], 0 jnz .err2 .dodel: push eax mov eax, [edi+20-2] mov ax, [edi+26] xchg eax, [esp] ; delete folder entry mov byte [edi], 0xE5 ; delete LFN (if present) .lfndel: cmp edi, buffer ja @f cmp [longname_sec2], 0 jz .lfndone push [longname_sec2] push [longname_sec1] pop [longname_sec2] and [longname_sec1], 0 push ebx mov ebx, buffer call hd_write mov eax, [esp+4] call hd_read pop ebx pop eax mov edi, buffer+0x200 @@: sub edi, 0x20 cmp byte [edi], 0xE5 jz .lfndone cmp byte [edi+11], 0xF jnz .lfndone mov byte [edi], 0xE5 jmp .lfndel .lfndone: push ebx mov ebx, buffer call hd_write pop ebx ; delete FAT chain pop eax call clear_cluster_chain call update_disk pop edi xor eax, eax cmp [hd_error], 0 jz @f mov al, 11 @@: ret ; \end{diamond}