0,0 → 1,3705 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; FAT32.INC ;; |
;; ;; |
;; FAT 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: 4273 $ |
|
|
cache_max equ 1919 ; max. is 1919*512+0x610000=0x6ffe00 |
|
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] |
|
; Internal data for every FAT partition. |
struct FAT PARTITION |
fs_type db ? |
fat16_root db 0 ; flag for fat16 rootdir |
fat_change db 0 ; 1=fat has changed |
db ? ; alignment |
Lock MUTEX ? ; currently operations with one partition |
; can not be executed in parallel since the |
; legacy code is not ready; this mutex guards |
; all operations |
SECTORS_PER_FAT dd 0x1f3a |
NUMBER_OF_FATS dd 0x2 |
SECTORS_PER_CLUSTER dd 0x8 |
BYTES_PER_SECTOR dd 0x200 ; Note: if BPS <> 512 need lots of changes |
ROOT_CLUSTER dd 2 ; first rootdir cluster |
FAT_START dd 0 ; start of fat table |
ROOT_START dd 0 ; start of rootdir (only fat16) |
ROOT_SECTORS dd 0 ; count of rootdir sectors (only fat16) |
DATA_START dd 0 ; start of data area (=first cluster 2) |
LAST_CLUSTER dd 0 ; last availabe cluster |
ADR_FSINFO dd 0 ; used only by fat32 |
|
fatRESERVED dd 0x0FFFFFF6 |
fatBAD dd 0x0FFFFFF7 |
fatEND dd 0x0FFFFFF8 |
fatMASK dd 0x0FFFFFFF |
|
fatStartScan dd 2 |
|
cluster_tmp dd 0 ; used by analyze_directory |
; and analyze_directory_to_write |
|
longname_sec1 dd 0 ; used by analyze_directory to save 2 previous |
longname_sec2 dd 0 ; directory sectors for delete long filename |
|
fat_in_cache dd -1 |
|
; For FAT16/FAT32, this points to 512-byte buffer for the current sector of FAT. |
; For FAT12, the entire FAT structure is read |
; and unpacked from 12bit per cluster to word per cluster. |
; |
; Note: work with unpacked copy of FAT12 means |
; additional memory and additional code for packing/unpacking. |
; I'm not sure that the economy justifies the cost, but anyway, |
; there is how work was done before my edits, and I'm just keeping the principle. |
fat_cache_ptr dd ? |
fat12_unpacked_ptr dd ? |
buffer rb 512 |
fsinfo_buffer rb 512 |
ends |
|
uglobal |
align 4 |
partition_count dd 0 ; partitions found by set_FAT32_variables |
|
hd_error dd 0 ; set by wait_for_sector_buffer |
hd_setup dd 0 |
hd_wait_timeout dd 0 |
|
cache_search_start dd 0 ; used by find_empty_slot |
endg |
|
uglobal |
align 4 |
Sector512: ; label for dev_hdcd.inc |
buffer: |
times 512 db 0 |
endg |
|
iglobal |
align 4 |
fat_user_functions: |
dd fat_free |
dd (fat_user_functions_end - fat_user_functions - 4) / 4 |
dd fat_Read |
dd fat_ReadFolder |
dd fat_Rewrite |
dd fat_Write |
dd fat_SetFileEnd |
dd fat_GetFileInfo |
dd fat_SetFileInfo |
dd 0 |
dd fat_Delete |
dd fat_CreateFolder |
fat_user_functions_end: |
endg |
|
; these labels are located before the main function to make |
; most of jumps to these be short |
fat_create_partition.free_return0: |
mov eax, ebp |
call free |
pop ebp |
fat_create_partition.return0: |
xor eax, eax |
ret |
fat_create_partition: |
; bootsector must have been successfully read |
cmp dword [esp+4], 0 |
jnz .return0 |
; bootsector signature must be correct |
cmp word [ebx+0x1fe], 0xaa55 |
jnz .return0 |
; sectors per cluster must be nonzero |
cmp byte [ebx+0xd], 0 |
jz .return0 |
; bytes per sector must be 0x200 |
cmp word [ebx+0xb], 0x200 |
jnz .return0 |
; number of fats must be nonzero |
cmp byte [ebx+0x10], 0 |
jz .return0 |
; The only reason to be invalid partition now is FAT12. Since the test for |
; FAT size requires knowledge of some calculated values, which are also used |
; in the normal operation, let's hope for the best and allocate data now; if |
; it will prove wrong, just deallocate it. |
movi eax, sizeof.FAT |
call malloc |
test eax, eax |
jz .return0 |
mov ecx, dword [ebp+PARTITION.FirstSector] |
mov dword [eax+FAT.FirstSector], ecx |
mov ecx, dword [ebp+PARTITION.FirstSector+4] |
mov dword [eax+FAT.FirstSector+4], ecx |
mov ecx, dword [ebp+PARTITION.Length] |
mov dword [eax+FAT.Length], ecx |
mov ecx, dword [ebp+PARTITION.Length+4] |
mov dword [eax+FAT.Length+4], ecx |
mov ecx, [ebp+PARTITION.Disk] |
mov [eax+FAT.Disk], ecx |
mov [eax+FAT.FSUserFunctions], fat_user_functions |
or [eax+FAT.fat_in_cache], -1 |
mov [eax+FAT.fat_change], 0 |
push ebp |
mov ebp, eax |
|
lea ecx, [ebp+FAT.Lock] |
call mutex_init |
|
movzx eax, word [ebx+0xe] ; sectors reserved |
mov [ebp+FAT.FAT_START], eax |
|
movzx eax, byte [ebx+0xd] ; sectors per cluster |
mov [ebp+FAT.SECTORS_PER_CLUSTER], eax |
|
movzx ecx, word [ebx+0xb] ; bytes per sector |
mov [ebp+FAT.BYTES_PER_SECTOR], ecx |
|
movzx eax, word [ebx+0x11] ; count of rootdir entries (=0 fat32) |
shl eax, 5 ; mul 32 |
dec ecx |
add eax, ecx ; round up if not equal count |
inc ecx ; bytes per sector |
xor edx, edx |
div ecx |
mov [ebp+FAT.ROOT_SECTORS], eax ; count of rootdir sectors |
|
movzx eax, word [ebx+0x16] ; sectors per fat <65536 |
test eax, eax |
jnz @f |
mov eax, [ebx+0x24] ; sectors per fat |
@@: |
mov [ebp+FAT.SECTORS_PER_FAT], eax |
|
movzx eax, byte [ebx+0x10] ; number of fats |
mov [ebp+FAT.NUMBER_OF_FATS], eax |
mul [ebp+FAT.SECTORS_PER_FAT] |
test edx, edx |
jnz .free_return0 |
add eax, [ebp+FAT.FAT_START] |
jc .free_return0 |
mov [ebp+FAT.ROOT_START], eax ; rootdir = fat_start + fat_size * fat_count |
add eax, [ebp+FAT.ROOT_SECTORS] ; rootdir sectors should be 0 on fat32 |
jc .free_return0 |
mov [ebp+FAT.DATA_START], eax ; data area = rootdir + rootdir_size |
|
movzx eax, word [ebx+0x13] ; total sector count <65536 |
test eax, eax |
jnz @f |
mov eax, [ebx+0x20] ; total sector count |
@@: |
; total sector count must not exceed partition size |
cmp dword [ebp+FAT.Length+4], 0 |
jnz @f |
cmp eax, dword [ebp+FAT.Length] |
ja .free_return0 |
@@: |
mov dword [ebp+FAT.Length], eax |
and dword [ebp+FAT.Length+4], 0 |
sub eax, [ebp+FAT.DATA_START] ; eax = count of data sectors |
jc .free_return0 |
xor edx, edx |
div [ebp+FAT.SECTORS_PER_CLUSTER] |
inc eax |
mov [ebp+FAT.LAST_CLUSTER], eax |
dec eax ; cluster count |
jz .free_return0 |
mov [ebp+FAT.fatStartScan], 2 |
|
; limits by Microsoft Hardware White Paper v1.03 |
cmp eax, 4085 ; 0xff5 |
jb .fat12 |
cmp eax, 65525 ; 0xfff5 |
jb .fat16 |
.fat32: |
mov eax, [ebx+0x2c] ; rootdir cluster |
mov [ebp+FAT.ROOT_CLUSTER], eax |
movzx eax, word [ebx+0x30] |
mov [ebp+FAT.ADR_FSINFO], eax |
push ebx |
add ebx, 512 |
call fs_read32_sys |
test eax, eax |
jnz @f |
mov eax, [ebx+0x1ec] |
cmp eax, -1 |
jz @f |
mov [ebp+FAT.fatStartScan], eax |
@@: |
pop ebx |
mov [ebp+FAT.fatRESERVED], 0x0FFFFFF6 |
mov [ebp+FAT.fatBAD], 0x0FFFFFF7 |
mov [ebp+FAT.fatEND], 0x0FFFFFF8 |
mov [ebp+FAT.fatMASK], 0x0FFFFFFF |
mov al, 32 |
.fat_not_12_finalize: |
mov [ebp+FAT.fs_type], al |
; For FAT16 and FAT32, allocate 512 bytes for FAT cache. |
mov eax, 512 |
call malloc |
test eax, eax |
jz .free_return0 |
mov [ebp+FAT.fat_cache_ptr], eax |
mov eax, ebp |
pop ebp |
ret |
.fat16: |
and [ebp+FAT.ROOT_CLUSTER], 0 |
mov [ebp+FAT.fatRESERVED], 0x0000FFF6 |
mov [ebp+FAT.fatBAD], 0x0000FFF7 |
mov [ebp+FAT.fatEND], 0x0000FFF8 |
mov [ebp+FAT.fatMASK], 0x0000FFFF |
mov al, 16 |
jmp .fat_not_12_finalize |
.fat12: |
and [ebp+FAT.ROOT_CLUSTER], 0 |
mov [ebp+FAT.fatRESERVED], 0xFF6 |
mov [ebp+FAT.fatBAD], 0xFF7 |
mov [ebp+FAT.fatEND], 0xFFF |
mov [ebp+FAT.fatMASK], 0xFFF |
mov al, 12 |
mov [ebp+FAT.fs_type], al |
; For FAT12, allocate&read data for entire table: |
; calculate A = ALIGN_UP(NUM_CLUSTERS, 8), |
; calculatefatchain/restorefatchain will process A items, |
; allocate ALIGN_UP(A*3/2, 512) bytes for FAT table plus A*2 bytes for unpacked data. |
mov eax, [ebp+FAT.LAST_CLUSTER] |
and eax, not 7 |
add eax, 8 |
mov edx, eax |
lea eax, [eax*3] |
add eax, 512*2-1 |
shr eax, 10 |
shl eax, 9 |
lea eax, [eax+edx*2] |
call malloc |
test eax, eax |
jz .free_return0 |
; Read ALIGN_UP(NUM_CLUSTERS*3/2, 512) bytes. |
; Note that this can be less than allocated, this is ok, |
; overallocation simplifies calculatefatchain/restorefatchain. |
push ebx |
mov [ebp+FAT.fat_cache_ptr], eax |
mov edx, [ebp+FAT.LAST_CLUSTER] |
lea edx, [(edx+1)*3 + 512*2-1] |
shr edx, 10 |
xchg eax, ebx |
xor eax, eax |
.read_fat: |
push eax |
add eax, [ebp+FAT.FAT_START] |
call fs_read32_sys |
test eax, eax |
pop eax |
jz @f |
dbgstr 'Failed to read FAT table' |
mov eax, [ebp+FAT.fat_cache_ptr] |
call free |
pop ebx |
jmp .free_return0 |
@@: |
add ebx, 512 |
inc eax |
cmp eax, edx |
jb .read_fat |
mov [ebp+FAT.fat12_unpacked_ptr], ebx |
call calculatefatchain |
pop ebx |
mov eax, ebp |
pop ebp |
ret |
|
fat_free: |
push eax |
mov eax, [eax+FAT.fat_cache_ptr] |
call free |
pop eax |
jmp free |
|
calculatefatchain: |
|
pushad |
|
mov esi, [ebp+FAT.fat_cache_ptr] |
mov edi, [ebp+FAT.fat12_unpacked_ptr] |
|
mov edx, [ebp+FAT.LAST_CLUSTER] |
and edx, not 7 |
lea edx, [edi+(edx+8)*2] |
push edx |
|
fcnew: |
mov eax, dword [esi] |
mov ebx, dword [esi+4] |
mov ecx, dword [esi+8] |
mov edx, ecx |
shr edx, 4;8 ok |
shr dx, 4;7 ok |
xor ch, ch |
shld ecx, ebx, 20;6 ok |
shr cx, 4;5 ok |
shld ebx, eax, 12 |
and ebx, 0x0fffffff;4 ok |
shr bx, 4;3 ok |
shl eax, 4 |
and eax, 0x0fffffff;2 ok |
shr ax, 4;1 ok |
mov dword [edi], eax |
mov dword [edi+4], ebx |
mov dword [edi+8], ecx |
mov dword [edi+12], edx |
add edi, 16 |
add esi, 12 |
|
cmp edi, [esp] |
jnz fcnew |
pop eax |
|
popad |
ret |
|
|
restorefatchain: ; restore fat chain |
|
pushad |
|
mov esi, [ebp+FAT.fat12_unpacked_ptr] |
mov edi, [ebp+FAT.fat_cache_ptr] |
|
mov edx, [ebp+FAT.LAST_CLUSTER] |
and edx, not 7 |
lea edx, [esi+(edx+8)*2] |
|
fcnew2: |
mov eax, dword [esi] |
mov ebx, dword [esi+4] |
shl ax, 4 |
shl eax, 4 |
shl bx, 4 |
shr ebx, 4 |
shrd eax, ebx, 8 |
shr ebx, 8 |
mov dword [edi], eax |
mov word [edi+4], bx |
add edi, 6 |
add esi, 8 |
|
cmp esi, edx |
jb fcnew2 |
|
mov esi, [ebp+FAT.NUMBER_OF_FATS] |
mov edx, [ebp+FAT.LAST_CLUSTER] |
lea edx, [(edx+1)*3 + 512*2-1] |
shr edx, 10 |
push [ebp+FAT.FAT_START] |
|
.write_fats: |
xor eax, eax |
mov ebx, [ebp+FAT.fat_cache_ptr] |
.loop1: |
push eax |
add eax, [esp+4] |
call fs_write32_sys |
test eax, eax |
pop eax |
jnz .fail |
add ebx, 512 |
inc eax |
cmp eax, edx |
jb .loop1 |
pop eax |
add eax, [ebp+FAT.SECTORS_PER_FAT] |
push eax |
dec esi |
jnz .write_fats |
pop eax |
|
popad |
ret |
.fail: |
dbgstr 'Failed to save FAT' |
popad |
ret |
|
iglobal |
label fat_legal_chars byte |
; 0 = not allowed |
; 1 = allowed only in long names |
; 3 = allowed |
times 32 db 0 |
; ! " # $ % & ' ( ) * + , - . / |
db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0 |
; 0 1 2 3 4 5 6 7 8 9 : ; < = > ? |
db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0 |
; @ A B C D E F G H I J K L M N O |
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 |
; P Q R S T U V W X Y Z [ \ ] ^ _ |
db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3 |
; ` a b c d e f g h i j k l m n o |
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 |
; p q r s t u v w x y z { | } ~ |
db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0 |
endg |
|
fat_name_is_legal: |
; in: esi->(long) name |
; out: CF set <=> legal |
; destroys eax |
push esi |
xor eax, eax |
@@: |
lodsb |
test al, al |
jz .done |
cmp al, 80h |
jae .big |
test [fat_legal_chars+eax], 1 |
jnz @b |
.err: |
pop esi |
clc |
ret |
.big: |
; 0x80-0xAF, 0xE0-0xEF |
cmp al, 0xB0 |
jb @b |
cmp al, 0xE0 |
jb .err |
cmp al, 0xF0 |
jb @b |
jmp .err |
.done: |
sub esi, [esp] |
cmp esi, 257 |
pop esi |
ret |
|
fat_next_short_name: |
; in: edi->8+3 name |
; out: name corrected |
; CF=1 <=> error |
pushad |
mov ecx, 8 |
mov al, '~' |
std |
push edi |
add edi, 7 |
repnz scasb |
pop edi |
cld |
jz .tilde |
; tilde is not found, insert "~1" at end |
add edi, 6 |
cmp word [edi], ' ' |
jnz .insert_tilde |
@@: |
dec edi |
cmp byte [edi], ' ' |
jz @b |
inc edi |
.insert_tilde: |
mov word [edi], '~1' |
popad |
clc |
ret |
.tilde: |
push edi |
add edi, 7 |
xor ecx, ecx |
@@: |
; after tilde may be only digits and trailing spaces |
cmp byte [edi], '~' |
jz .break |
cmp byte [edi], ' ' |
jz .space |
cmp byte [edi], '9' |
jnz .found |
dec edi |
jmp @b |
.space: |
dec edi |
inc ecx |
jmp @b |
.found: |
inc byte [edi] |
add dword [esp], 8 |
jmp .zerorest |
.break: |
jecxz .noplace |
inc edi |
mov al, '1' |
@@: |
xchg al, [edi] |
inc edi |
cmp al, ' ' |
mov al, '0' |
jnz @b |
.succ: |
pop edi |
popad |
clc |
ret |
.noplace: |
dec edi |
cmp edi, [esp] |
jz .err |
add dword [esp], 8 |
mov word [edi], '~1' |
inc edi |
inc edi |
@@: |
mov byte [edi], '0' |
.zerorest: |
inc edi |
cmp edi, [esp] |
jb @b |
pop edi |
popad |
;clc ; automatically |
ret |
.err: |
pop edi |
popad |
stc |
ret |
|
fat_gen_short_name: |
; in: esi->long name |
; edi->buffer (8+3=11 chars) |
; out: buffer filled |
pushad |
mov eax, ' ' |
push edi |
stosd |
stosd |
stosd |
pop edi |
xor eax, eax |
movi ebx, 8 |
lea ecx, [edi+8] |
.loop: |
lodsb |
test al, al |
jz .done |
call char_toupper |
cmp al, ' ' |
jz .space |
cmp al, 80h |
ja .big |
test [fat_legal_chars+eax], 2 |
jnz .symbol |
.inv_symbol: |
mov al, '_' |
or bh, 1 |
.symbol: |
cmp al, '.' |
jz .dot |
.normal_symbol: |
dec bl |
jns .store |
mov bl, 0 |
.space: |
or bh, 1 |
jmp .loop |
.store: |
stosb |
jmp .loop |
.big: |
cmp al, 0xB0 |
jb .normal_symbol |
cmp al, 0xE0 |
jb .inv_symbol |
cmp al, 0xF0 |
jb .normal_symbol |
jmp .inv_symbol |
.dot: |
test bh, 2 |
jz .firstdot |
pop ebx |
add ebx, edi |
sub ebx, ecx |
push ebx |
cmp ebx, ecx |
jb @f |
pop ebx |
push ecx |
@@: |
cmp edi, ecx |
jbe .skip |
@@: |
dec edi |
mov al, [edi] |
dec ebx |
mov [ebx], al |
mov byte [edi], ' ' |
cmp edi, ecx |
ja @b |
.skip: |
mov bh, 3 |
jmp @f |
.firstdot: |
cmp bl, 8 |
jz .space |
push edi |
or bh, 2 |
@@: |
mov edi, ecx |
mov bl, 3 |
jmp .loop |
.done: |
test bh, 2 |
jz @f |
pop edi |
@@: |
lea edi, [ecx-8] |
test bh, 1 |
jz @f |
call fat_next_short_name |
@@: |
popad |
ret |
|
fat12_free_space: |
;--------------------------------------------- |
; |
; returns free space in edi |
; rewr.by Mihasik |
;--------------------------------------------- |
|
push eax ebx ecx |
|
mov edi, [ebp+FAT.fat12_unpacked_ptr];start of FAT |
xor ax, ax;Free cluster=0x0000 in FAT |
xor ebx, ebx;counter |
mov ecx, [ebp+FAT.LAST_CLUSTER] |
inc ecx |
cld |
rdfs1: |
repne scasw |
jnz rdfs2 ;if last cluster not 0 |
inc ebx |
test ecx, ecx |
jnz rdfs1 |
rdfs2: |
shl ebx, 9;free clusters*512 |
mov edi, ebx |
|
pop ecx ebx eax |
ret |
|
|
|
set_FAT: |
;-------------------------------- |
; input : EAX = cluster |
; EDX = value to save |
; EBP = pointer to FAT structure |
; output : EDX = old value |
;-------------------------------- |
; out: CF set <=> error |
push eax ebx esi |
|
cmp eax, 2 |
jb sfc_error |
cmp eax, [ebp+FAT.LAST_CLUSTER] |
ja sfc_error |
cmp [ebp+FAT.fs_type], 12 |
je set_FAT12 |
cmp [ebp+FAT.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, [ebp+FAT.FAT_START] |
mov ebx, [ebp+FAT.fat_cache_ptr] |
|
cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory? |
je sfc_in_cache ; yes |
|
cmp [ebp+FAT.fat_change], 0; is fat changed? |
je sfc_no_change ; no |
call write_fat_sector; yes. write it into disk |
jc sfc_error |
|
sfc_no_change: |
mov [ebp+FAT.fat_in_cache], eax; save fat sector |
call fs_read32_sys |
test eax, eax |
jne sfc_error |
|
|
sfc_in_cache: |
cmp [ebp+FAT.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, [ebp+FAT.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 [ebp+FAT.fat_change], 1; fat has changed |
|
sfc_nonzero: |
and edx, [ebp+FAT.fatMASK] |
|
sfc_return: |
pop esi ebx eax |
ret |
sfc_error: |
stc |
jmp sfc_return |
|
set_FAT12: |
test edx, 0xF000 |
jnz sfc_error |
mov ebx, [ebp+FAT.fat12_unpacked_ptr] |
xchg [ebx+eax*2], dx |
mov [ebp+FAT.fat_change], 1 |
pop esi ebx eax |
clc |
ret |
|
get_FAT: |
;-------------------------------- |
; input : EAX = cluster |
; EBP = pointer to FAT structure |
; output : EAX = next cluster |
;-------------------------------- |
; out: CF set <=> error |
push ebx esi |
|
cmp [ebp+FAT.fs_type], 12 |
je get_FAT12 |
|
cmp [ebp+FAT.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, [ebp+FAT.FAT_START] |
mov ebx, [ebp+FAT.fat_cache_ptr] |
|
cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory? |
je gfc_in_cache |
|
cmp [ebp+FAT.fat_change], 0; is fat changed? |
je gfc_no_change ; no |
call write_fat_sector; yes. write it into disk |
jc hd_error_01 |
|
gfc_no_change: |
mov [ebp+FAT.fat_in_cache], eax |
call fs_read32_sys |
test eax, eax |
jne hd_error_01 |
|
gfc_in_cache: |
mov eax, [ebx+esi] |
and eax, [ebp+FAT.fatMASK] |
gfc_return: |
pop esi ebx |
ret |
hd_error_01: |
stc |
jmp gfc_return |
|
get_FAT12: |
mov ebx, [ebp+FAT.fat12_unpacked_ptr] |
movzx eax, word [ebx+eax*2] |
pop esi ebx |
clc |
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, [ebp+FAT.LAST_CLUSTER]; counter for full disk |
mov eax, [ebp+FAT.fatStartScan] |
cmp [ebp+FAT.fs_type], 12 |
jz get_free_FAT12 |
dec ecx |
cmp eax, 2 |
jb gff_reset |
|
gff_test: |
cmp eax, [ebp+FAT.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 |
jc 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? |
jnz gff_test ; no |
|
gff_not_found: |
pop ecx ; yes. disk is full |
stc |
ret |
|
gff_not_found_1: |
pop eax |
jmp gff_not_found |
|
gff_found: |
lea ecx, [eax+1] |
mov [ebp+FAT.fatStartScan], ecx |
pop ecx |
clc |
ret |
|
get_free_FAT12: |
push edx edi |
mov edi, [ebp+FAT.fat12_unpacked_ptr] |
cmp eax, 2 |
jb .reset |
cmp eax, ecx |
jbe @f |
.reset: |
mov eax, 2 |
@@: |
mov edx, eax |
lea edi, [edi+eax*2] |
sub ecx, eax |
inc ecx |
xor eax, eax |
repnz scasw |
jz .found |
cmp edx, 2 |
jz .notfound |
mov edi, [ebp+FAT.fat12_unpacked_ptr] |
lea ecx, [edx-2] |
repnz scasw |
jnz .notfound |
.found: |
sub edi, [ebp+FAT.fat12_unpacked_ptr] |
shr edi, 1 |
mov [ebp+FAT.fatStartScan], edi |
lea eax, [edi-1] |
pop edi edx ecx |
ret |
.notfound: |
pop edi edx ecx |
stc |
ret |
|
|
write_fat_sector: |
;----------------------------------------------------------- |
; write changed fat to disk |
;----------------------------------------------------------- |
push eax ebx ecx |
|
mov [ebp+FAT.fat_change], 0 |
mov eax, [ebp+FAT.fat_in_cache] |
cmp eax, -1 |
jz write_fat_not_used |
mov ebx, [ebp+FAT.fat_cache_ptr] |
mov ecx, [ebp+FAT.NUMBER_OF_FATS] |
|
write_next_fat: |
push eax |
call fs_write32_sys |
test eax, eax |
pop eax |
jnz write_fat_not_used |
|
add eax, [ebp+FAT.SECTORS_PER_FAT] |
dec ecx |
jnz write_next_fat |
|
write_fat_not_used: |
pop ecx ebx eax |
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 [ebp+FAT.fs_type], 32 ; free disk space only used by fat32 |
jne add_dfs_no |
|
push eax ebx |
mov eax, [ebp+FAT.ADR_FSINFO] |
lea ebx, [ebp+FAT.fsinfo_buffer] |
call fs_read32_sys |
test eax, eax |
jnz add_not_fs |
|
cmp dword [ebx+0x1fc], 0xaa550000; check sector id |
jne add_not_fs |
|
add [ebx+0x1e8], ecx |
push [ebp+FAT.fatStartScan] |
pop dword [ebx+0x1ec] |
mov eax, [ebp+FAT.ADR_FSINFO] |
call fs_write32_sys |
; jc add_not_fs |
|
add_not_fs: |
pop ebx eax |
|
add_dfs_no: |
ret |
|
|
|
clear_cluster_chain: |
;----------------------------------------------------- |
; input : eax = first cluster |
;----------------------------------------------------- |
push eax ecx edx |
xor ecx, ecx ; cluster count |
|
clean_new_chain: |
cmp eax, [ebp+FAT.LAST_CLUSTER]; end of file |
ja delete_OK |
cmp eax, 2 ; unfinished fat chain or zero length file |
jb delete_OK |
cmp eax, [ebp+FAT.ROOT_CLUSTER]; don't remove root cluster |
jz delete_OK |
|
xor edx, edx |
call set_FAT ; clear fat entry |
jc 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 |
clc |
access_denied_01: |
pop edx ecx eax |
ret |
|
|
if 0 |
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 [ebp+FAT.fs_type], 16 |
jz info_fat_ok |
cmp [ebp+FAT.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, [ebp+FAT.LAST_CLUSTER] |
|
info_cluster: |
push eax |
call get_FAT ; get cluster info |
jc 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, [ebp+FAT.SECTORS_PER_CLUSTER], 512; cluster size in bytes |
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 |
end if |
|
update_disk: |
cmp [ebp+FAT.fat_change], 0 ; is fat changed? |
je upd_no_change |
cmp [ebp+FAT.fs_type], 12 |
jz .fat12 |
;----------------------------------------------------------- |
; write changed fat and cache to disk |
;----------------------------------------------------------- |
|
call write_fat_sector |
jc update_disk_acces_denied |
jmp upd_no_change |
.fat12: |
call restorefatchain |
mov [ebp+FAT.fat_change], 0 |
|
upd_no_change: |
|
push esi |
mov esi, [ebp+PARTITION.Disk] |
call disk_sync |
pop esi |
update_disk_acces_denied: |
ret |
|
fat_lock: |
lea ecx, [ebp+FAT.Lock] |
jmp mutex_lock |
fat_unlock: |
lea ecx, [ebp+FAT.Lock] |
jmp mutex_unlock |
|
; \begin{diamond} |
uni2ansi_str: |
; convert UNICODE zero-terminated string to ASCII-string (codepage 866) |
; in: esi->source, edi->buffer (may be esi=edi) |
; destroys: eax,esi,edi |
lodsw |
test ax, ax |
jz .done |
cmp ax, 0x80 |
jb .ascii |
cmp ax, 0x401 |
jz .yo1 |
cmp ax, 0x451 |
jz .yo2 |
cmp ax, 0x410 |
jb .unk |
cmp ax, 0x440 |
jb .rus1 |
cmp ax, 0x450 |
jb .rus2 |
.unk: |
mov al, '_' |
jmp .doit |
.yo1: |
mov al, 0xF0 ; 'Ё' |
jmp .doit |
.yo2: |
mov al, 0xF1 ; 'ё' |
jmp .doit |
.rus1: |
; 0x410-0x43F -> 0x80-0xAF |
add al, 0x70 |
jmp .doit |
.rus2: |
; 0x440-0x44F -> 0xE0-0xEF |
add al, 0xA0 |
.ascii: |
.doit: |
stosb |
jmp uni2ansi_str |
.done: |
mov byte [edi], 0 |
ret |
|
ansi2uni_char: |
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding |
mov ah, 0 |
; 0x00-0x7F - trivial map |
cmp al, 0x80 |
jb .ret |
; 0x80-0xAF -> 0x410-0x43F |
cmp al, 0xB0 |
jae @f |
add ax, 0x410-0x80 |
.ret: |
ret |
@@: |
; 0xE0-0xEF -> 0x440-0x44F |
cmp al, 0xE0 |
jb .unk |
cmp al, 0xF0 |
jae @f |
add ax, 0x440-0xE0 |
ret |
; 0xF0 -> 0x401 |
; 0xF1 -> 0x451 |
@@: |
cmp al, 0xF0 ; 'Ё' |
jz .yo1 |
cmp al, 0xF1 ; 'ё' |
jz .yo2 |
.unk: |
mov al, '_' ; ah=0 |
ret |
.yo1: |
mov ax, 0x401 |
ret |
.yo2: |
mov ax, 0x451 |
ret |
|
char_toupper: |
; convert character to uppercase, using cp866 encoding |
; in: al=symbol |
; out: al=converted symbol |
cmp al, 'a' |
jb .ret |
cmp al, 'z' |
jbe .az |
cmp al, 0xF1 ; 'ё' |
jz .yo1 |
cmp al, 0xA0 ; 'а' |
jb .ret |
cmp al, 0xE0 ; 'р' |
jb .rus1 |
cmp al, 0xEF ; 'я' |
ja .ret |
; 0xE0-0xEF -> 0x90-0x9F |
sub al, 0xE0-0x90 |
.ret: |
ret |
.rus1: |
; 0xA0-0xAF -> 0x80-0x8F |
.az: |
and al, not 0x20 |
ret |
.yo1: |
; 0xF1 -> 0xF0 |
dec ax |
ret |
|
fat_get_name: |
; in: edi->FAT entry |
; out: CF=1 - no valid entry |
; else CF=0 and ebp->ASCIIZ-name |
; (maximum length of filename is 255 (wide) symbols without trailing 0, |
; but implementation requires buffer 261 words) |
; destroys eax |
cmp byte [edi], 0 |
jz .no |
cmp byte [edi], 0xE5 |
jnz @f |
.no: |
stc |
ret |
@@: |
cmp byte [edi+11], 0xF |
jz .longname |
test byte [edi+11], 8 |
jnz .no |
push ecx |
push edi ebp |
test byte [ebp-4], 1 |
jnz .unicode_short |
|
mov eax, [edi] |
mov ecx, [edi+4] |
mov [ebp], eax |
mov [ebp+4], ecx |
|
mov ecx, 8 |
@@: |
cmp byte [ebp+ecx-1], ' ' |
loope @b |
|
mov eax, [edi+8] |
cmp al, ' ' |
je .done |
shl eax, 8 |
mov al, '.' |
|
lea ebp, [ebp+ecx+1] |
mov [ebp], eax |
mov ecx, 3 |
@@: |
rol eax, 8 |
cmp al, ' ' |
jne .done |
loop @b |
dec ebp |
.done: |
and byte [ebp+ecx+1], 0 ; CF=0 |
pop ebp edi ecx |
ret |
.unicode_short: |
mov ecx, 8 |
push ecx |
@@: |
mov al, [edi] |
inc edi |
call ansi2uni_char |
mov [ebp], ax |
inc ebp |
inc ebp |
loop @b |
pop ecx |
@@: |
cmp word [ebp-2], ' ' |
jnz @f |
dec ebp |
dec ebp |
loop @b |
@@: |
mov word [ebp], '.' |
inc ebp |
inc ebp |
mov ecx, 3 |
push ecx |
@@: |
mov al, [edi] |
inc edi |
call ansi2uni_char |
mov [ebp], ax |
inc ebp |
inc ebp |
loop @b |
pop ecx |
@@: |
cmp word [ebp-2], ' ' |
jnz @f |
dec ebp |
dec ebp |
loop @b |
dec ebp |
dec ebp |
@@: |
and word [ebp], 0 ; CF=0 |
pop ebp edi ecx |
ret |
.longname: |
; LFN |
mov al, byte [edi] |
and eax, 0x3F |
dec eax |
cmp al, 20 |
jae .no ; ignore invalid entries |
mov word [ebp+260*2], 0 ; force null-terminating for orphans |
imul eax, 13*2 |
add ebp, eax |
test byte [edi], 0x40 |
jz @f |
mov word [ebp+13*2], 0 |
@@: |
push eax |
; now copy name from edi to ebp ... |
mov eax, [edi+1] |
mov [ebp], eax ; symbols 1,2 |
mov eax, [edi+5] |
mov [ebp+4], eax ; 3,4 |
mov eax, [edi+9] |
mov [ebp+8], ax ; 5 |
mov eax, [edi+14] |
mov [ebp+10], eax ; 6,7 |
mov eax, [edi+18] |
mov [ebp+14], eax ; 8,9 |
mov eax, [edi+22] |
mov [ebp+18], eax ; 10,11 |
mov eax, [edi+28] |
mov [ebp+22], eax ; 12,13 |
; ... done |
pop eax |
sub ebp, eax |
test eax, eax |
jz @f |
; if this is not first entry, more processing required |
stc |
ret |
@@: |
; if this is first entry: |
test byte [ebp-4], 1 |
jnz .ret |
; buffer at ebp contains UNICODE name, convert it to ANSI |
push esi edi |
mov esi, ebp |
mov edi, ebp |
call uni2ansi_str |
pop edi esi |
.ret: |
clc |
ret |
|
fat_compare_name: |
; compares ASCIIZ-names, case-insensitive (cp866 encoding) |
; in: esi->name, ebp->name |
; out: if names match: ZF=1 and esi->next component of name |
; else: ZF=0, esi is not changed |
; destroys eax |
push ebp esi |
.loop: |
mov al, [ebp] |
inc ebp |
call char_toupper |
push eax |
lodsb |
call char_toupper |
cmp al, [esp] |
jnz .done |
pop eax |
test al, al |
jnz .loop |
dec esi |
pop eax |
pop ebp |
xor eax, eax ; set ZF flag |
ret |
.done: |
cmp al, '/' |
jnz @f |
cmp byte [esp], 0 |
jnz @f |
mov [esp+4], esi |
@@: |
pop eax |
pop esi ebp |
ret |
|
fat_find_lfn: |
; in: esi->name |
; [esp+4] = next |
; [esp+8] = first |
; [esp+C]... - possibly parameters for first and next |
; out: CF=1 - file not found, eax=error code |
; else CF=0, esi->next name component, edi->direntry |
pusha |
lea eax, [esp+0Ch+20h] |
call dword [eax-4] |
jc .reterr |
sub esp, 262*2 ; reserve place for LFN |
push 0 ; for fat_get_name: read ASCII name |
.l1: |
lea ebp, [esp+4] |
call fat_get_name |
jc .l2 |
call fat_compare_name |
jz .found |
.l2: |
mov ebp, [esp+8+262*2+4] |
lea eax, [esp+0Ch+20h+262*2+4] |
call dword [eax-8] |
jnc .l1 |
add esp, 262*2+4 |
.reterr: |
mov [esp+28], eax |
stc |
popa |
ret |
.found: |
add esp, 262*2+4 |
mov ebp, [esp+8] |
; if this is LFN entry, advance to true entry |
cmp byte [edi+11], 0xF |
jnz @f |
lea eax, [esp+0Ch+20h] |
call dword [eax-8] |
jc .reterr |
@@: |
add esp, 8 ; CF=0 |
push esi |
push edi |
popa |
ret |
|
fat_time_to_bdfe: |
; in: eax=FAT time |
; out: eax=BDFE time |
push ecx edx |
mov ecx, eax |
mov edx, eax |
shr eax, 11 |
shl eax, 16 ; hours |
and edx, 0x1F |
add edx, edx |
mov al, dl ; seconds |
shr ecx, 5 |
and ecx, 0x3F |
mov ah, cl ; minutes |
pop edx ecx |
ret |
|
fat_date_to_bdfe: |
push ecx edx |
mov ecx, eax |
mov edx, eax |
shr eax, 9 |
add ax, 1980 |
shl eax, 16 ; year |
and edx, 0x1F |
mov al, dl ; day |
shr ecx, 5 |
and ecx, 0xF |
mov ah, cl ; month |
pop edx ecx |
ret |
|
bdfe_to_fat_time: |
push edx |
mov edx, eax |
shr eax, 16 |
and dh, 0x3F |
shl eax, 6 |
or al, dh |
shr dl, 1 |
and dl, 0x1F |
shl eax, 5 |
or al, dl |
pop edx |
ret |
|
bdfe_to_fat_date: |
push edx |
mov edx, eax |
shr eax, 16 |
sub ax, 1980 |
and dh, 0xF |
shl eax, 4 |
or al, dh |
and dl, 0x1F |
shl eax, 5 |
or al, dl |
pop edx |
ret |
|
fat_entry_to_bdfe: |
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi |
; destroys eax |
mov eax, [ebp-4] |
mov [esi+4], eax ; ASCII/UNICODE name |
fat_entry_to_bdfe2: |
movzx eax, byte [edi+11] |
mov [esi], eax ; attributes |
movzx eax, word [edi+14] |
call fat_time_to_bdfe |
mov [esi+8], eax ; creation time |
movzx eax, word [edi+16] |
call fat_date_to_bdfe |
mov [esi+12], eax ; creation date |
and dword [esi+16], 0 ; last access time is not supported on FAT |
movzx eax, word [edi+18] |
call fat_date_to_bdfe |
mov [esi+20], eax ; last access date |
movzx eax, word [edi+22] |
call fat_time_to_bdfe |
mov [esi+24], eax ; last write time |
movzx eax, word [edi+24] |
call fat_date_to_bdfe |
mov [esi+28], eax ; last write date |
mov eax, [edi+28] |
mov [esi+32], eax ; file size (low dword) |
xor eax, eax |
mov [esi+36], eax ; file size (high dword) |
test ebp, ebp |
jz .ret |
push ecx edi |
lea edi, [esi+40] |
mov esi, ebp |
test byte [esi-4], 1 |
jz .ansi |
mov ecx, 260/2 |
rep movsd |
mov [edi-2], ax |
@@: |
mov esi, edi |
pop edi ecx |
.ret: |
ret |
.ansi: |
mov ecx, 264/4 |
rep movsd |
mov [edi-1], al |
jmp @b |
|
bdfe_to_fat_entry: |
; convert BDFE at edx to FAT entry at edi |
; destroys eax |
; attributes byte |
test byte [edi+11], 8 ; volume label? |
jnz @f |
mov al, [edx] |
and al, 0x27 |
and byte [edi+11], 0x10 |
or byte [edi+11], al |
@@: |
mov eax, [edx+8] |
call bdfe_to_fat_time |
mov [edi+14], ax ; creation time |
mov eax, [edx+12] |
call bdfe_to_fat_date |
mov [edi+16], ax ; creation date |
mov eax, [edx+20] |
call bdfe_to_fat_date |
mov [edi+18], ax ; last access date |
mov eax, [edx+24] |
call bdfe_to_fat_time |
mov [edi+22], ax ; last write time |
mov eax, [edx+28] |
call bdfe_to_fat_date |
mov [edi+24], ax ; last write date |
ret |
|
hd_find_lfn: |
; in: ebp -> FAT structure |
; in: esi+[esp+4] -> name |
; out: CF=1 - file not found, eax=error code |
; else CF=0 and edi->direntry, eax=sector |
; destroys eax |
push esi edi |
push 0 |
push 0 |
push fat1x_root_first |
push fat1x_root_next |
mov eax, [ebp+FAT.ROOT_CLUSTER] |
cmp [ebp+FAT.fs_type], 32 |
jz .fat32 |
.loop: |
and [ebp+FAT.longname_sec1], 0 |
and [ebp+FAT.longname_sec2], 0 |
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 4 |
.found: |
lea eax, [esp+4+24] |
cmp dword [eax], 0 |
jz @f |
mov esi, [eax] |
and dword [eax], 0 |
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, [ebp+FAT.ROOT_START] |
.cmn: |
add esp, 20 ; CF=0 |
pop esi |
ret 4 |
|
;---------------------------------------------------------------- |
; fat_Read - FAT implementation of reading a file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Read: |
call fat_lock |
push edi |
cmp byte [esi], 0 |
jnz @f |
.noaccess: |
pop edi |
.noaccess_2: |
call fat_unlock |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
|
@@: |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push eax |
call fat_unlock |
pop eax |
or ebx, -1 |
ret |
|
.found: |
test byte [edi+11], 0x10; do not allow read directories |
jnz .noaccess |
cmp dword [ebx+8], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
call fat_unlock |
mov eax, ERROR_END_OF_FILE |
pop edi |
ret |
@@: |
mov ecx, [ebx+12] ; size |
mov edx, [ebx+16] ; pointer |
mov ebx, [ebx+4] ; file offset |
push 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 |
cmp eax, 2 |
jb .eof |
cmp eax, [ebp+FAT.fatRESERVED] |
jae .eof |
mov [ebp+FAT.cluster_tmp], eax |
dec eax |
dec eax |
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER] |
imul eax, edi |
add eax, [ebp+FAT.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 eax ebx |
mov ebx, edx |
call fs_read32_app |
test eax, eax |
pop ebx eax |
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 |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_app |
test eax, eax |
mov eax, ebx |
pop ebx |
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, [ebp+FAT.cluster_tmp] |
call get_FAT |
jc .noaccess_1 |
|
jmp .new_cluster |
.noaccess_3: |
pop eax |
.noaccess_1: |
pop eax |
push ERROR_DEVICE |
.done: |
mov ebx, edx |
call fat_unlock |
pop eax edx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx |
sub ebx, edx |
jmp .reteof |
|
;---------------------------------------------------------------- |
; fat_ReadFolder - FAT implementation of reading a folder |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_ReadFolder: |
call fat_lock |
mov eax, [ebp+FAT.ROOT_CLUSTER] |
push edi |
cmp byte [esi], 0 |
jz .doit |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push eax |
call fat_unlock |
pop eax |
or ebx, -1 |
ret |
.found: |
test byte [edi+11], 0x10 ; do not allow read files |
jnz .found_dir |
pop edi |
call fat_unlock |
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 |
sub esp, 262*2 ; reserve space for LFN |
push dword [ebx+8] ; for fat_get_name: read ANSI/UNICODE name |
mov edx, [ebx+16] ; pointer to buffer |
; init header |
push eax |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
pop eax |
mov byte [edx], 1 ; version |
mov esi, edi ; esi points to BDFE |
mov ecx, [ebx+12] ; number of blocks to read |
mov ebx, [ebx+4] ; index of the first block |
.new_cluster: |
mov [ebp+FAT.cluster_tmp], eax |
test eax, eax |
jnz @f |
cmp [ebp+FAT.fs_type], 32 |
jz .notfound |
mov eax, [ebp+FAT.ROOT_START] |
push [ebp+FAT.ROOT_SECTORS] |
push ebx |
jmp .new_sector |
@@: |
dec eax |
dec eax |
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
push [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
push ebx |
.new_sector: |
lea ebx, [ebp+FAT.buffer] |
mov edi, ebx |
push eax |
call fs_read32_sys |
test eax, eax |
pop eax |
jnz .notfound2 |
add ebx, 512 |
push eax |
.l1: |
push ebp |
lea ebp, [esp+20] |
call fat_get_name |
pop ebp |
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, [ebp+FAT.cluster_tmp] |
test eax, eax |
jz .done |
call get_FAT |
jc .notfound2 |
cmp eax, 2 |
jb .done |
cmp eax, [ebp+FAT.fatRESERVED] |
jae .done |
push eax |
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
mov [esp+8], eax |
pop eax |
mov [ebp+FAT.cluster_tmp], eax |
dec eax |
dec eax |
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
@@: |
lea ebx, [ebp+FAT.buffer] |
mov edi, ebx |
push eax |
call fs_read32_sys |
test eax, eax |
pop eax |
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 |
push ebp |
lea ebp, [esp+20] |
call fat_entry_to_bdfe |
pop ebp |
.l2: |
add edi, 0x20 |
cmp edi, ebx |
jb .l1 |
pop eax |
inc eax |
dec dword [esp+4] |
jnz .new_sector |
mov eax, [ebp+FAT.cluster_tmp] |
test eax, eax |
jz .done |
call get_FAT |
jc .notfound2 |
cmp eax, 2 |
jb .done |
cmp eax, [ebp+FAT.fatRESERVED] |
jae .done |
push eax |
mov eax, [ebp+FAT.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 esi edi |
mov ebx, [edx+4] |
call fat_unlock |
mov eax, ERROR_DEVICE |
ret |
.done: |
add esp, 262*2+4+8 |
mov ebx, [edx+4] |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
push eax |
call fat_unlock |
pop eax |
pop esi edi |
ret |
|
fat1x_root_next: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200-0x20] |
cmp edi, ecx |
jae fat1x_root_next_sector |
pop ecx |
add edi, 0x20 |
ret ; CF=0 |
fat1x_root_next_sector: |
; read next sector |
push [ebp+FAT.longname_sec2] |
pop [ebp+FAT.longname_sec1] |
mov ecx, [eax+4] |
push ecx |
add ecx, [ebp+FAT.ROOT_START] |
mov [ebp+FAT.longname_sec2], ecx |
pop ecx |
inc ecx |
mov [eax+4], ecx |
cmp ecx, [ebp+FAT.ROOT_SECTORS] |
pop ecx |
jb fat1x_root_first |
mov eax, ERROR_FILE_NOT_FOUND |
stc |
ret |
fat1x_root_first: |
mov eax, [eax+4] |
add eax, [ebp+FAT.ROOT_START] |
push ebx |
lea edi, [ebp+FAT.buffer] |
mov ebx, edi |
call fs_read32_sys |
pop ebx |
test eax, eax |
jnz .readerr |
ret ; CF=0 |
.readerr: |
mov eax, ERROR_DEVICE |
stc |
ret |
.notfound: |
mov eax, ERROR_FILE_NOT_FOUND |
stc |
ret |
fat1x_root_begin_write: |
push edi eax |
call fat1x_root_first |
pop eax edi |
ret |
fat1x_root_end_write: |
pusha |
mov eax, [eax+4] |
add eax, [ebp+FAT.ROOT_START] |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
popa |
ret |
fat1x_root_next_write: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200] |
cmp edi, ecx |
jae @f |
pop ecx |
ret |
@@: |
call fat1x_root_end_write |
jmp fat1x_root_next_sector |
fat1x_root_extend_dir: |
stc |
ret |
|
fat_notroot_next: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200-0x20] |
cmp edi, ecx |
jae fat_notroot_next_sector |
pop ecx |
add edi, 0x20 |
ret ; CF=0 |
fat_notroot_next_sector: |
push [ebp+FAT.longname_sec2] |
pop [ebp+FAT.longname_sec1] |
push eax |
call fat_get_sector |
mov [ebp+FAT.longname_sec2], eax |
pop eax |
mov ecx, [eax+4] |
inc ecx |
cmp ecx, [ebp+FAT.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 |
jc fat_notroot_first.deverr |
cmp ecx, 2 |
jb fat_notroot_next_err |
cmp ecx, [ebp+FAT.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 |
lea edi, [ebp+FAT.buffer] |
mov ebx, edi |
call fs_read32_sys |
pop ebx |
test eax, eax |
jz .ret ; CF=0 |
push ecx |
.deverr: |
pop ecx |
mov eax, ERROR_DEVICE |
stc |
.ret: |
ret |
fat_notroot_next_err: |
pop ecx |
mov eax, ERROR_FILE_NOT_FOUND |
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 |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
pop ebx |
ret |
fat_notroot_next_write: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200] |
cmp edi, ecx |
jae @f |
pop ecx |
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, [ebp+FAT.fatEND] |
call set_FAT |
jc .writeerr |
mov edx, eax |
mov eax, [esp+4] |
mov eax, [eax] |
push edx |
call set_FAT |
pop edx |
jnc @f |
.writeerr: |
pop edx |
pop eax |
stc |
ret |
@@: |
push ecx |
or ecx, -1 |
call add_disk_free_space |
; zero new cluster |
mov ecx, 512/4 |
lea edi, [ebp+FAT.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, [ebp+FAT.SECTORS_PER_CLUSTER] |
imul eax, ecx |
add eax, [ebp+FAT.DATA_START] |
mov ebx, edi |
@@: |
push eax |
call fs_write32_sys |
pop eax |
inc eax |
loop @b |
pop ecx ebx eax |
clc |
ret |
|
fat_get_sector: |
push ecx |
mov ecx, [eax] |
dec ecx |
dec ecx |
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER] |
add ecx, [ebp+FAT.DATA_START] |
add ecx, [eax+4] |
mov eax, ecx |
pop ecx |
ret |
|
fshrad: |
call fat_unlock |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
|
;---------------------------------------------------------------- |
; fat_CreateFolder - FAT implementation of creating a folder |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_CreateFolder: |
push 1 |
jmp fat_Rewrite.common |
|
;---------------------------------------------------------------- |
; fat_Rewrite - FAT implementation of creating a new file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Rewrite: |
push 0 |
.common: |
call fat_lock |
pop eax |
cmp byte [esi], 0 |
jz fshrad |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
pushad |
xor edi, edi |
mov edx, [esp+4+20h] |
push esi |
test edx, edx |
jz @f |
mov esi, edx |
@@: |
lodsb |
test al, al |
jz @f |
cmp al, '/' |
jnz @b |
lea edi, [esi-1] |
jmp @b |
@@: |
pop esi |
test edi, edi |
jnz .noroot |
test edx, edx |
jnz .hasebp |
mov edx, [ebp+FAT.ROOT_CLUSTER] |
cmp [ebp+FAT.fs_type], 32 |
jz .pushnotroot |
xor edx, edx |
push edx |
push fat1x_root_extend_dir |
push fat1x_root_end_write |
push fat1x_root_next_write |
push fat1x_root_begin_write |
push edx |
push edx |
push fat1x_root_first |
push fat1x_root_next |
jmp .common1 |
.hasebp: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [edx], 0 |
jz .ret1 |
stdcall hd_find_lfn, 0 |
mov esi, [esp+4+20h] |
jc .ret1 |
jmp .common0 |
.noroot: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [edi+1], 0 |
jz .ret1 |
; check existence |
mov byte [edi], 0 |
push edi |
stdcall hd_find_lfn, [esp+4+24h] |
pop esi |
mov byte [esi], '/' |
jnc @f |
.notfound0: |
mov eax, ERROR_FILE_NOT_FOUND |
.ret1: |
mov [esp+28], eax |
call fat_unlock |
popad |
xor ebx, ebx |
ret |
@@: |
inc esi |
.common0: |
test byte [edi+11], 0x10 ; must be directory |
mov eax, ERROR_ACCESS_DENIED |
jz .ret1 |
mov edx, [edi+20-2] |
mov dx, [edi+26] ; ebp=cluster |
mov eax, ERROR_FAT_TABLE |
cmp edx, 2 |
jb .ret1 |
.pushnotroot: |
push edx |
push fat_notroot_extend_dir |
push fat_notroot_end_write |
push fat_notroot_next_write |
push fat_notroot_begin_write |
push 0 |
push edx |
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, 36 |
call fat_unlock |
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+36+28], 0 |
jz @f |
add esp, 36 |
call fat_unlock |
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, [ebp+FAT.fatRESERVED] |
jae .done1 |
push edx |
xor edx, edx |
call set_FAT |
mov eax, edx |
pop edx |
jc .done1 |
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, 36 |
call fat_unlock |
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 edx, [eax+24] |
mov [eax], edx |
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+36 |
call fat_unlock |
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 |
movi eax, 1 ; 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 edx, [eax+24] |
mov [eax], edx |
and dword [eax+4], 0 |
call dword [eax-4] |
pop eax |
jnc .scan_dir |
.fsfrfe3: |
add esp, 12+8+12+36 |
call fat_unlock |
popad |
mov eax, ERROR_DEVICE |
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] |
mov edx, eax |
pop eax |
jnc .scan_dir |
cmp edx, ERROR_DEVICE |
jz .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+36 |
call fat_unlock |
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! |
push esi ecx |
; If creating a directory, allocate one data cluster now and fail immediately |
; if this is impossible. This prevents from creating an invalid directory entry |
; on a full disk. |
; yup, the argument is quite non-intuitive... but what should I do if |
; the entire function uses such arguments? BTW, it refers to al from pushad, |
; which in turn is filled with 0 in fat_Rewrite and 1 in fat_CreateFolder. |
cmp byte [esp+8+12+8+12+36+28], 0 |
jz .no.preallocate.folder.data |
call get_free_FAT |
jnc @f |
add esp, 8+12+8 |
jmp .disk_full |
@@: |
mov [esp+8+12+8+12+36+20], eax ; store the cluster somewhere |
.no.preallocate.folder.data: |
; calculate name checksum |
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 fat_read_symbols |
mov ax, 0xF |
stosw |
mov al, [esp+4] |
stosb |
mov cl, 6 |
call fat_read_symbols |
xor eax, eax |
stosw |
mov cl, 2 |
call fat_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+36+28], cl |
jz .doit |
; create directory |
mov byte [edi+11], 10h ; attributes: folder |
mov esi, edi |
lea eax, [esp+8] |
call dword [eax+16] ; flush directory |
mov eax, [esp+36+20] ; extract saved cluster |
mov [esp+36+20], edi ; this is needed for calculating arg of add_disk_free_space! |
push ecx |
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER] |
shl ecx, 9 |
push ecx |
push edi |
jmp .doit2 |
.doit: |
mov esi, [esp+36+20] |
lea eax, [esp+8] |
call dword [eax+16] ; flush directory |
push ecx |
mov ecx, [esp+4+36+24] |
push ecx |
push edi |
test ecx, ecx |
jz .done |
call get_free_FAT |
jc .diskfull |
.doit2: |
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, [ebp+FAT.fatEND] |
call set_FAT |
pop edx |
.write_cluster: |
push eax |
dec eax |
dec eax |
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
push [ebp+FAT.SECTORS_PER_CLUSTER] |
; write data |
.write_sector: |
cmp byte [esp+20+36+28], 0 |
jnz .writedir |
mov ecx, 512 |
cmp dword [esp+12], ecx |
jb .writeshort |
; we can write directly from given buffer |
mov ebx, esi |
add esi, ecx |
jmp .writecommon |
.writeshort: |
mov ecx, [esp+12] |
push ecx |
lea edi, [ebp+FAT.buffer] |
mov ebx, edi |
rep movsb |
.writedircont: |
lea ecx, [ebp+FAT.buffer+0x200] |
sub ecx, edi |
push eax |
xor eax, eax |
rep stosb |
pop eax |
pop ecx |
.writecommon: |
push eax |
call fs_write32_app |
test eax, eax |
pop eax |
jnz .writeerr |
inc eax |
sub dword [esp+12], ecx |
jz .writedone |
dec dword [esp] |
jnz .write_sector |
pop eax |
; allocate new cluster |
pop eax |
mov ecx, eax |
call get_free_FAT |
jc .diskfull |
push edx |
mov edx, [ebp+FAT.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 eax |
sub esi, ecx |
mov eax, ERROR_DEVICE |
jmp .ret |
.writedone: |
pop eax eax |
.done: |
xor eax, eax |
.ret: |
pop edi ecx |
sub esi, [esp+4+36+20] |
mov [esp+4+36+28], eax |
mov [esp+4+36+16], esi |
lea eax, [esp+12] |
call dword [eax+8] |
mov [edi+28], esi |
call dword [eax+16] |
mov [esp+36+16], ebx |
lea eax, [esi+511] |
shr eax, 9 |
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER] |
lea eax, [eax+ecx-1] |
xor edx, edx |
div ecx |
pop ecx |
sub ecx, eax |
call add_disk_free_space |
add esp, 36 |
call update_disk |
call fat_unlock |
popad |
ret |
.writedir: |
push 512 |
lea edi, [ebp+FAT.buffer] |
mov ebx, edi |
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER] |
shl ecx, 9 |
cmp ecx, [esp+16] |
jnz .writedircont |
dec dword [esp+20] |
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+36] |
cmp ecx, [ebp+FAT.ROOT_CLUSTER] |
jnz @f |
xor ecx, ecx |
@@: |
mov word [edi-32+26], cx |
shr ecx, 16 |
mov [edi-32+20], cx |
jmp .writedircont |
|
fat_read_symbol: |
or ax, -1 |
test esi, esi |
jz .retFFFF |
lodsb |
test al, al |
jnz ansi2uni_char |
xor eax, eax |
xor esi, esi |
.retFFFF: |
ret |
|
fat_read_symbols: |
call fat_read_symbol |
stosw |
loop fat_read_symbols |
ret |
|
|
fat_Write.access_denied: |
push ERROR_ACCESS_DENIED |
fat_Write.ret0: |
pop eax |
xor ebx, ebx |
ret |
|
fat_Write.ret11: |
push ERROR_DEVICE |
jmp fat_Write.ret0 |
|
;---------------------------------------------------------------- |
; fat_Write - FAT implementation of writing to file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Write: |
cmp byte [esi], 0 |
jz .access_denied |
call fat_lock |
push edi |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push eax |
call fat_unlock |
jmp .ret0 |
.found: |
; FAT does not support files larger than 4GB |
cmp dword [ebx+8], 0 |
jz @f |
.eof: |
pop edi |
push ERROR_END_OF_FILE |
call fat_unlock |
jmp .ret0 |
@@: |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
mov ebx, [ebx+4] |
; 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 edx |
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 |
call fat_unlock |
pop eax |
pop eax |
pop ecx |
pop edx |
pop edi |
xor ebx, ebx |
ret |
.disk_full: |
; correct number of bytes to write |
mov ecx, [edi+28] |
cmp ecx, ebx |
ja .length_ok |
push 0 |
.ret: |
pop eax |
sub edx, [esp+12] |
mov ebx, edx ; ebx=number of written bytes |
call update_disk |
test eax, eax |
jz @f |
mov byte [esp+4], ERROR_DEVICE |
@@: |
call fat_unlock |
pop eax |
pop eax |
pop ecx |
pop edx |
pop edi |
ret |
.length_ok: |
mov esi, [edi+28] |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov edi, eax ; edi=current cluster |
push 0 ; current sector in cluster |
; save directory |
mov eax, [esp+12] |
push ebx |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
pop ebx |
test eax, eax |
jz @f |
.device_err: |
mov byte [esp+8], ERROR_DEVICE |
jmp .ret |
.fat_err: |
mov byte [esp+8], ERROR_FAT_TABLE |
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+4], 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, [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
add eax, [esp+4] |
; load sector if needed |
cmp dword [esp+8], 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 eax ebx |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_app |
test eax, eax |
pop ebx eax |
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+8+12] |
jbe @f |
lea edi, [ebp+FAT.buffer] |
add edi, [esp+8+12] |
rep stosb |
@@: |
; zero uninitialized data in the last sector |
mov ecx, 0x200 |
sub ecx, esi |
jbe @f |
lea edi, [ebp+FAT.buffer+esi] |
rep stosb |
@@: |
pop edi ecx |
; copy new data |
mov eax, edx |
neg ebx |
jecxz @f |
lea ebx, [ebp+FAT.buffer+0x200+ebx] |
call memmove |
xor ebx, ebx |
@@: |
pop eax |
; save sector |
push ebx |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_app |
pop ebx |
test eax, eax |
jnz .device_err2 |
add edx, ecx |
sub [esp], ecx |
pop ecx |
jz .ret |
.skip: |
; next sector |
pop eax |
inc eax |
push eax |
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
jb @f |
and dword [esp], 0 |
mov eax, edi |
call get_FAT |
mov edi, eax |
jc .device_err |
cmp edi, 2 |
jb .fat_err |
cmp edi, [ebp+FAT.fatRESERVED] |
jae .fat_err |
@@: |
sub esi, 0x200 |
jae @f |
xor esi, esi |
@@: |
sub dword [esp+4], 0x200 |
jae @f |
and dword [esp+4], 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 ERROR_DEVICE) |
hd_extend_file: |
push esi |
mov esi, [ebp+FAT.SECTORS_PER_CLUSTER] |
imul esi, [ebp+FAT.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, esi |
jbe .last_found |
call get_FAT |
jnc @f |
.device_err: |
pop ecx |
.device_err2: |
pop esi |
push ERROR_DEVICE |
.ret_err: |
pop eax |
stc |
ret |
@@: |
cmp eax, 2 |
jb .fat_err |
cmp eax, [ebp+FAT.fatRESERVED] |
jb .last_loop |
.fat_err: |
pop ecx esi |
push ERROR_FAT_TABLE |
jmp .ret_err |
.last_found: |
push eax |
call get_FAT |
jnc @f |
pop eax |
jmp .device_err |
@@: |
cmp eax, [ebp+FAT.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, [ebp+FAT.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 |
add [edi+28], esi |
jmp .extend_loop |
.extend_done: |
mov [edi+28], ecx |
pop edx esi |
xor eax, eax ; CF=0 |
ret |
.device_err3: |
pop edx |
jmp .device_err2 |
.disk_full: |
pop eax edx esi |
movi eax, ERROR_DISK_FULL |
stc |
ret |
|
fat_update_datetime: |
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 |
ret |
|
|
;---------------------------------------------------------------- |
; fat_SetFileEnd - FAT implementation of setting end-of-file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_SetFileEnd: |
call fat_lock |
push edi |
cmp byte [esi], 0 |
jnz @f |
.access_denied: |
push ERROR_ACCESS_DENIED |
.ret: |
call fat_unlock |
pop eax |
pop edi |
ret |
@@: |
stdcall hd_find_lfn, [esp+4+4] |
jnc @f |
.reteax: |
push eax |
jmp .ret |
@@: |
; must not be directory |
test byte [edi+11], 10h |
jnz .access_denied |
; file size must not exceed 4 Gb |
cmp dword [ebx+8], 0 |
jz @f |
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+4] |
cmp eax, [edi+28] |
jb .truncate |
ja .expand |
pop eax |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
test eax, eax |
jz @f |
push ERROR_DEVICE |
jmp .ret |
@@: |
push 0 |
jmp .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 ecx ebp ebx ecx |
jmp .reteax |
.expand_ok: |
.disk_full: |
; save directory |
mov eax, [edi+28] |
xchg eax, [esp+20] |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
test eax, eax |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov edi, eax |
jz @f |
.pop_ret11: |
mov byte [esp], ERROR_DEVICE |
jmp .pop_ret |
@@: |
test edi, edi |
jz .pop_ret |
; now zero new data |
push 0 |
; edi=current cluster, [esp]=sector in cluster |
; [esp+24]=new size, [esp+8]=old size, [esp+4]=return code |
.zero_loop: |
cmp edi, 2 |
jb .error_fat |
cmp edi, [ebp+FAT.fatRESERVED] |
jae .error_fat |
sub dword [esp+8], 0x200 |
jae .next_cluster |
lea eax, [edi-2] |
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
add eax, [esp] |
cmp dword [esp+8], -0x200 |
jz .noread |
push eax |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_app |
test eax, eax |
pop eax |
jnz .err_next |
.noread: |
mov ecx, [esp+8] |
neg ecx |
push edi |
lea edi, [ebp+FAT.buffer+0x200] |
add edi, [esp+12] |
push eax |
xor eax, eax |
mov [esp+16], eax |
rep stosb |
pop eax |
pop edi |
call fs_write32_app |
test eax, eax |
jz .next_cluster |
.err_next: |
mov byte [esp+4], ERROR_DEVICE |
.next_cluster: |
pop eax |
sub dword [esp+20], 0x200 |
jbe .pop_ret |
inc eax |
push eax |
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
jb .zero_loop |
and dword [esp], 0 |
mov eax, edi |
call get_FAT |
mov edi, eax |
jnc .zero_loop |
pop eax |
jmp .pop_ret11 |
.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 |
@@: |
cmp ecx, 2 |
jb .error_fat2 |
cmp ecx, [ebp+FAT.fatRESERVED] |
jae .error_fat2 |
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
shl eax, 9 |
sub [esp], eax |
jbe @f |
mov eax, ecx |
call get_FAT |
mov ecx, eax |
jnc @b |
.device_err3: |
pop eax ecx eax edi |
call update_disk |
call fat_unlock |
movi eax, ERROR_DEVICE |
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, [ebp+FAT.fatEND] |
call set_FAT |
mov eax, edx |
pop edx |
jnc @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 |
jc .device_err4 |
; save directory |
mov eax, [esp+12] |
push ebx |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
pop ebx |
test eax, eax |
jnz .device_err4 |
; zero last sector, ignore errors |
pop ecx |
pop eax |
dec ecx |
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER] |
add ecx, [ebp+FAT.DATA_START] |
push eax |
sar eax, 9 |
add ecx, eax |
pop eax |
and eax, 0x1FF |
jz .truncate_done |
push ebx eax |
mov eax, ecx |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_app |
pop eax |
lea edi, [ebp+FAT.buffer+eax] |
push ecx |
mov ecx, 0x200 |
sub ecx, eax |
xor eax, eax |
rep stosb |
pop eax |
call fs_write32_app |
pop ebx |
.truncate_done: |
pop ecx eax edi |
call update_disk |
call fat_unlock |
xor eax, eax |
ret |
.error_fat: |
pop eax |
mov byte [esp], ERROR_FAT_TABLE |
jmp .pop_ret |
.error_fat2: |
pop eax ecx eax edi |
call update_disk |
call fat_unlock |
movi eax, ERROR_FAT_TABLE |
ret |
|
;---------------------------------------------------------------- |
; fat_GetFileInfo - FAT implementation of getting file info |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_GetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call fat_lock |
stdcall hd_find_lfn, [esp+4+4] |
jc .error |
push ebp |
xor ebp, ebp |
mov esi, [ebx+16] |
mov dword [esi+4], ebp |
call fat_entry_to_bdfe2 |
pop ebp |
call fat_unlock |
xor eax, eax |
pop edi |
ret |
.error: |
push eax |
call fat_unlock |
pop eax |
pop edi |
ret |
|
;---------------------------------------------------------------- |
; fat_SetFileInfo - FAT implementation of setting file info |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_SetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call fat_lock |
stdcall hd_find_lfn, [esp+4+4] |
jc .error |
push eax |
mov edx, [ebx+16] |
call bdfe_to_fat_entry |
pop eax |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
call update_disk |
call fat_unlock |
pop edi |
xor eax, eax |
ret |
.error: |
push eax |
call fat_unlock |
pop eax |
pop edi |
ret |
|
;---------------------------------------------------------------- |
; fat_Delete - FAT implementation of deleting a file/folder |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Delete: |
call fat_lock |
cmp byte [esi], 0 |
jnz @f |
; cannot delete root! |
.access_denied: |
push ERROR_ACCESS_DENIED |
.pop_ret: |
call fat_unlock |
pop eax |
xor ebx, ebx |
ret |
@@: |
and [ebp+FAT.longname_sec1], 0 |
and [ebp+FAT.longname_sec2], 0 |
push edi |
stdcall hd_find_lfn, [esp+4+4] |
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 esi, [edi+20-2] |
mov si, [edi+26] |
xor ecx, ecx |
lea eax, [esi-2] |
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_sys |
test eax, eax |
jnz .err1 |
lea eax, [ebx+0x200] |
add ebx, 2*0x20 |
.checkempty: |
cmp byte [ebx], 0 |
jz .empty |
cmp byte [ebx], 0xE5 |
jnz .notempty |
add ebx, 0x20 |
cmp ebx, eax |
jb .checkempty |
inc ecx |
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER] |
jb @f |
mov eax, esi |
call get_FAT |
jc .err1 |
cmp eax, 2 |
jb .error_fat |
cmp eax, [ebp+FAT.fatRESERVED] |
jae .empty |
mov esi, eax |
xor ecx, ecx |
@@: |
lea eax, [esi-2] |
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER] |
add eax, [ebp+FAT.DATA_START] |
add eax, ecx |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_sys |
test eax, eax |
lea eax, [ebx+0x200] |
jz .checkempty |
.err1: |
popad |
.err2: |
pop edi |
call fat_unlock |
movi eax, ERROR_DEVICE |
ret |
.error_fat: |
popad |
pop edi |
call fat_unlock |
movi eax, ERROR_FAT_TABLE |
ret |
.notempty: |
popad |
.access_denied2: |
pop edi |
call fat_unlock |
movi eax, ERROR_ACCESS_DENIED |
ret |
.empty: |
popad |
push eax ebx |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_sys |
test eax, eax |
pop ebx eax |
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: |
lea edx, [ebp+FAT.buffer] |
cmp edi, edx |
ja @f |
cmp [ebp+FAT.longname_sec2], 0 |
jz .lfndone |
push [ebp+FAT.longname_sec2] |
push [ebp+FAT.longname_sec1] |
pop [ebp+FAT.longname_sec2] |
and [ebp+FAT.longname_sec1], 0 |
push ebx |
mov ebx, edx |
call fs_write32_sys |
mov eax, [esp+4] |
call fs_read32_sys |
pop ebx |
pop eax |
lea edi, [ebp+FAT.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 |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
pop ebx |
; delete FAT chain |
pop eax |
call clear_cluster_chain |
call update_disk |
call fat_unlock |
pop edi |
xor eax, eax |
ret |
|
; \end{diamond} |