;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2021-2024. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License. ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; exFAT external functions ; in: ; ebx -> parameter structure of sysfunc 70 ; ebp -> exFAT structure ; esi -> path string in UTF-8 ; out: ; eax, ebx = return values for sysfunc 70 iglobal align 4 exFAT_user_functions: dd exFAT_free dd (exFAT_user_functions_end - exFAT_user_functions - 8) / 4 dd exFAT_ReadFile dd exFAT_ReadFolder dd 0 ;exFAT_CreateFile dd 0 ;exFAT_Write dd 0 ;exFAT_SetFileEnd dd exFAT_GetFileInfo dd exFAT_SetFileInfo dd 0 dd exFAT_Delete dd 0 ;exFAT_CreateFolder dd 0 ;exFAT_Rename exFAT_user_functions_end: endg struct exFAT PARTITION fat_change db ? ; 1=fat has changed ClstHeap_change db ? ; 1=Cluster Heap has changed createOption db ? rb 2 Lock MUTEX ; currently operations with one partition ; can not be executed in parallel since the legacy code is not ready FAT_START dd ? ; start of fat table ROOT_START dd ? ; start of rootdir SECTORS_PER_CLUSTER dd ? BYTES_PER_SECTOR dd ? ; Note: if BPS <> 512 need lots of changes SECTORS_PER_FAT dd ? NUMBER_OF_FATS dd ? CLUSTER_HEAP_START dd ? CLUSTER_COUNT dd ? DATA_START dd ? ; start of data area (=first cluster 2) LAST_CLUSTER dd ? ; last availabe cluster fatRESERVED dd ? fatBAD dd ? fatEND dd ? fatMASK dd ? fatStartScan dd ? cluster_tmp dd ? ; used by analyze_directory and analyze_directory_to_write ROOT_CLUSTER dd ? ; first rootdir cluster points_to_BDFE dd ? secondary_dir_entry dd ? longname_sec1 dd ? ; used by analyze_directory to save 2 previous longname_sec2 dd ? ; directory sectors for delete long filename longname_sector1 dd ? ; used by analyze_directory to save 2 previous longname_sector2 dd ? ; directory sectors for delete long filename LFN_reserve_place dd ? path_in_UTF8 dd ? General_Sec_Flags dd ? valid_data_length dd ? RAX_high dd ? RCX_high dd ? RDX_high dd ? RDI_high dd ? current_hash dd ? hash_flag dd ? need_hash dd ? buffer_curr_sector dd ? buff_file_dirsect dd ? buff_file_dir_pos dd ? fname_extdir_offset dd ? fat_in_cache dd ? fat_cache_ptr dd ? ClstHeap_in_cache dd ? ClstHeap_cache_ptr dd ? volumeLabel rb 12 ; The next areas (32*19) should be arranged sequentially. ; Do not change their location!!! file_dir_entry rb 32 ; Entry Type 0x85 str_ext_dir_entry rb 32 ; Entry Type 0xC0 fname_ext_dir_entry rb 32*17 ; Entry Type 0xC1 * 17 Entries buffer rb 512 ends ; these labels are located before the main function to make ; most of jumps to these be short exFAT_create_partition.free_return0: mov eax, ebp call free pop ebp ; DEBUGF 1, "K : exFAT_create_partition.free_return0 EAX: %x\n", eax exFAT_create_partition.return0: xor eax, eax ; DEBUGF 1, "K : exFAT_create_partition.return0 EAX: %x\n", eax ret ; Mount if it's a valid exFAT partition. exFAT_create_partition: ; DEBUGF 1, "K : exFAT_create_partition EAX: %x\n", eax ; in: ; ebp -> PARTITION structure ; ebx -> boot sector ; ebx+512 -> buffer ; out: ; eax -> exFAT structure, 0 = not exFAT cmp dword [esi+DISK.MediaInfo.SectorSize], 512 jnz .return0 ; DEBUGF 1, "K : exFAT DISK.MediaInfo.SectorSize=512\n" ; bootsector must have been successfully read cmp dword [esp+4], 0 jnz .return0 ; DEBUGF 1, "K : exFAT bootsector successfully read\n" ; offset +510 = bootsector signature must be correct cmp word [ebx+0x1fe], 0xaa55 jnz .return0 ; DEBUGF 1, "K : exFAT bootsector signature correct\n" ; offset +109 = sectors per cluster must be nonzero cmp byte [ebx+0x6d], 0 jz .return0 ; DEBUGF 1, "K : exFAT sectors per cluster = nonzero\n" ; offset +108 = bytes per sector must be 0x200 ; (LEGACY! In the future, increase support to 4096) ; the value for exFAT is a power of 2 cmp byte [ebx+0x6c], 9 jnz .return0 ; DEBUGF 1, "K : exFAT bytes per sector = 512\n" ; Test name = 'EXFAT ' cmp dword [ebx+3], 'EXFA' jnz .return0 cmp dword [ebx+7], 'T ' jnz .return0 ; DEBUGF 1, "K : exFAT Test name EXFAT = OK \n" movi eax, sizeof.exFAT call malloc test eax, eax jz .return0 ; DEBUGF 1, "K : exFAT malloc sizeof.exFAT = OK \n" mov ecx, dword [ebp+PARTITION.FirstSector] mov dword [eax+exFAT.FirstSector], ecx ; DEBUGF 1, "K : exFAT PARTITION.FirstSector ECX: %x\n", ecx mov ecx, dword [ebp+PARTITION.FirstSector+4] mov dword [eax+exFAT.FirstSector+4], ecx ; DEBUGF 1, "K : exFAT PARTITION.FirstSector+4 ECX: %x\n", ecx mov ecx, dword [ebp+PARTITION.Length] mov dword [eax+exFAT.Length], ecx ; DEBUGF 1, "K : exFAT PARTITION.Length ECX: %x\n", ecx mov ecx, dword [ebp+PARTITION.Length+4] mov dword [eax+exFAT.Length+4], ecx ; DEBUGF 1, "K : exFAT PARTITION.Length+4 ECX: %x\n", ecx mov ecx, [ebp+PARTITION.Disk] mov [eax+exFAT.Disk], ecx ; DEBUGF 1, "K : exFAT PARTITION.Disk ECX: %x\n", ecx mov [eax+exFAT.FSUserFunctions], exFAT_user_functions or [eax+exFAT.fat_in_cache], -1 mov [eax+exFAT.fat_change], 0 push ebp mov ebp, eax lea ecx, [ebp+exFAT.Lock] call mutex_init ; offset +80 = sectors reserved mov eax, [ebx+0x50] mov [ebp+exFAT.FAT_START], eax ; DEBUGF 1, "K : exFAT.FAT_START EAX: %x\n", eax ; offset +109 = sectors per cluster. This is power of 2; Minimal value is 1; ; 2^0 =1 sector (512 Bytes) and maximum 32 MB cluster size in bytes movzx ecx, byte [ebx+0x6d] mov eax, 1 shl eax, cl mov [ebp+exFAT.SECTORS_PER_CLUSTER], eax ; DEBUGF 1, "K : exFAT.SECTORS_PER_CLUSTER EAX: %x\n", eax ; offset +108 = bytes per sector. This is power of 2; Minimal value is 9; ; 2^9 =512 Bytes and maximum 2^12 =4096 Bytes movzx ecx, byte [ebx+0x6c] ; bytes per sector mov eax, 1 shl eax, cl mov [ebp+exFAT.BYTES_PER_SECTOR], eax ; DEBUGF 1, "K : exFAT.BYTES_PER_SECTOR EAX: %x\n", eax ;------------------------------------------------------------------------------ ; 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 ;------------------------------------------------------------------------------ ; offset +84 = Size of FAT in sectors mov eax, [ebx+0x54] ; sectors per fat mov [ebp+exFAT.SECTORS_PER_FAT], eax ; DEBUGF 1, "K : exFAT.SECTORS_PER_FAT EAX: %x\n", eax ;------------------------------------------------------------------------------ ; offset +88 = Starting sector of cluster heap mov eax, [ebx+0x58] ; Cluster offset mov [ebp+exFAT.CLUSTER_HEAP_START], eax ; DEBUGF 1, "K : exFAT.CLUSTER_HEAP_START EAX: %x\n", eax ;------------------------------------------------------------------------------ ; offset +92 = Number of clusters mov eax, [ebx+0x5c] ; Cluster count mov [ebp+exFAT.CLUSTER_COUNT], eax ; DEBUGF 1, "K : exFAT.CLUSTER_COUNT EAX: %x\n", eax ;------------------------------------------------------------------------------ ; offset +110 = Either 1 or 2; if TexFAT is supported then it will be 2 movzx eax, byte [ebx+0x6e] ; number of fats mov [ebp+exFAT.NUMBER_OF_FATS], eax ; DEBUGF 1, "K : exFAT.NUMBER_OF_FATS EAX: %x\n", eax mul [ebp+exFAT.SECTORS_PER_FAT] ; DEBUGF 1, "K : exFAT.SECTORS_PER_FAT mul EAX: %x\n", eax ; test edx, edx ; jnz .free_return0 add eax, [ebp+exFAT.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+exFAT.DATA_START], eax ; DEBUGF 1, "K : exFAT.DATA_START EAX: %x\n", eax ;------------------------------------------------------------------------------ ; offset +72 = Total number of Sectors mov eax, [ebx+0x48+4] ; total sector count high part test eax, eax jnz .free_return0 ; 32-BIT LIMIT - MODIFY LATER WITY RASP !!! ; DEBUGF 1, "K : exFAT Total number of Sectors+4 EAX: %x\n", eax mov eax, [ebx+0x48] ; total sector count low part ; DEBUGF 1, "K : exFAT Total number of Sectors EAX: %x\n", eax cmp dword [ebp+exFAT.Length+4], 0 jnz @f ; DEBUGF 1, "K : exFAT.Length+4 = 0\n" cmp eax, dword [ebp+exFAT.Length] ja .free_return0 ; DEBUGF 1, "K : exFAT.Length >= Total number of Sectors\n" @@: mov dword [ebp+exFAT.Length], eax and dword [ebp+exFAT.Length+4], 0 sub eax, [ebp+exFAT.DATA_START] ; eax = count of data sectors jc .free_return0 ; DEBUGF 1, "K : EAX - exFAT.DATA_START EAX: %x\n", eax xor edx, edx div [ebp+exFAT.SECTORS_PER_CLUSTER] inc eax mov [ebp+exFAT.LAST_CLUSTER], eax ; DEBUGF 1, "K : exFAT.LAST_CLUSTER EAX: %x\n", eax dec eax ; cluster count jz .free_return0 ; DEBUGF 1, "K : exFAT.LAST_CLUSTER >= 2 EAX: %x\n",eax mov [ebp+exFAT.fatStartScan], 2 ; cmp eax, 0xfff5 ; jb .fat16 ;------------------------------------------------------------------------------ ;.fat32: ; pusha ; lea esi, [ebx+71] ; lea edi, [ebp+exFAT.volumeLabel] ; movsd ; movsd ; movsd ; popa ;------------------------------------------------------------------------------ ; offset +96 = First cluster of root directory mov eax, [ebx+0x60] ; rootdir cluster mov [ebp+exFAT.ROOT_CLUSTER], eax ; DEBUGF 1, "K : exFAT.ROOT_CLUSTER EAX: %x\n", eax dec eax dec eax imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] add eax, [ebp+exFAT.CLUSTER_HEAP_START] mov [ebp+exFAT.ROOT_START], eax ; DEBUGF 1, "K : exFAT.ROOT_START EAX: %x\n", 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+exFAT.fatStartScan], eax ;@@: ; pop ebx ;------------------------------------------------------------------------------ mov [ebp+exFAT.fatRESERVED], 0x0FFFFFF6 mov [ebp+exFAT.fatBAD], 0x0FFFFFF7 mov [ebp+exFAT.fatEND], 0x0FFFFFF8 mov [ebp+exFAT.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. ; For exFAT allocate 512 bytes for Cluster Heap cache. mov eax, 512*2 call malloc test eax, eax jz .free_return0 mov [ebp+exFAT.fat_cache_ptr], eax add eax, 512 mov [ebp+exFAT.ClstHeap_cache_ptr], eax ; DEBUGF 1, "K : malloc exFAT.fat_cache_ptr EAX: %x\n", eax mov eax, ebp pop ebp ret ;------------------------------------------------------------------------------ exFAT_free: push eax mov eax, [eax+exFAT.fat_cache_ptr] ; DEBUGF 1, "K : exFAT_free exFAT.fat_cache_ptr EAX: %x\n", eax call free pop eax jmp free ;------------------------------------------------------------------------------ exFAT_lock: ; DEBUGF 1, "K : exFAT_lock \n" lea ecx, [ebp+exFAT.Lock] jmp mutex_lock exFAT_unlock: ; DEBUGF 1, "K : exFAT_unlock \n" lea ecx, [ebp+exFAT.Lock] jmp mutex_unlock ;------------------------------------------------------------------------------ exFAT_get_name: cmp byte [edi], 0 jz .no ; DEBUGF 1, "K : exFAT_get_name EDI:%x [EDI]:%x\n", edi, [edi] ; push ebp ; mov ebp,[esp+12+8+4+4+7*4+262*2+4+4] ; DEBUGF 1, "K : exFAT_get_name START Input FS EBP:%x\n", ebp ; pop ebp ; in: edi -> FAT entry, esi -> buffer for UTF-16 name ; out: CF=1 -> no valid entry cmp byte [edi], 0x85 ; File/Folder Directory Entry of ExFAT jz .file_directory_entry cmp byte [edi], 0xC0 ; Stream Extension Directory Entry of ExFAT jz .stream_extension_directory_entry cmp byte [edi], 0xC1 ; File Name Extension Directory Entry of ExFAT jz .longname push edi esi xchg esi, edi ; DEBUGF 1, "K : exFAT Volume label dword [ESI]: %x\n", [esi] cmp byte [esi], 0x83 ; Indicates that the Volume label exists jnz .no_label .label: ; DEBUGF 1, "K : exFAT_get_name.label \n" add esi, 2 lea edi, [ebp+exFAT.volumeLabel] push ecx mov ecx, 12 call UTF16to8_string pop ecx ; push edi ; lea edi, [ebp+exFAT.volumeLabel] ; DEBUGF 1, "K : exFAT Volume label: %s\n", edi ; pop edi .no_label: ; DEBUGF 1, "K : exFAT_get_name.no_label \n" pop esi edi .no: ; DEBUGF 1, "K : exFAT_get_name.no \n" stc ret ;-------------------------------------- .save_curr_sector_number: mov eax, [ebp+exFAT.buffer_curr_sector] cmp eax, [ebp+exFAT.longname_sector2] je @f push [ebp+exFAT.longname_sector2] pop [ebp+exFAT.longname_sector1] mov [ebp+exFAT.longname_sector2], eax @@: ret ;-------------------------------------- .file_directory_entry: ; DEBUGF 1, "K : exFAT_get_name 0x85\n" mov eax, [ebp+exFAT.buffer_curr_sector] mov [ebp+exFAT.buff_file_dirsect], eax mov [ebp+exFAT.buff_file_dir_pos], edi lea eax, [ebp+exFAT.fname_ext_dir_entry] mov [ebp+exFAT.fname_extdir_offset], eax xor eax, eax mov [ebp+exFAT.longname_sector1], eax mov [ebp+exFAT.longname_sector2], eax mov [ebp+exFAT.hash_flag], eax ; dword 0 mov al, byte [edi+1] ; Number of Secondary directory entries dec eax mov [ebp+exFAT.secondary_dir_entry], eax ; DEBUGF 1, "K : exFAT_get_name 0x85 SDE: %x\n", eax lea esi, [ebp+exFAT.file_dir_entry] ; DEBUGF 1, "K : exFAT.file_dir_entry ESI: %x [ESI]: %x\n", esi, [esi] jmp @f ;-------------------------------------- .stream_extension_directory_entry: ; DEBUGF 1, "K : exFAT_get_name 0xC0\n" ; DEBUGF 1, "K : exFAT SEDE need_hash :%x\n", [ebp+exFAT.need_hash] call .save_curr_sector_number mov eax, [ebp+exFAT.need_hash] test eax, eax jz .stream_extension_directory_entry_1 ; @f movzx eax, word [edi+4] ; hash of the file name ; DEBUGF 1, "K : exFAT hash 1 :%x\n", eax ; DEBUGF 1, "K : exFAT hash 2 :%x\n", [ebp+exFAT.current_hash] cmp eax, [ebp+exFAT.current_hash] je .stream_extension_directory_entry_1 ; @f xor eax, eax inc eax mov [ebp+exFAT.hash_flag], eax ; dword 1 ; DEBUGF 1, "K : exFAT hashes don't match! \n" .stream_extension_directory_entry_1: lea esi, [ebp+exFAT.str_ext_dir_entry] ; DEBUGF 1, "K : exFAT.str_ext_dir_entry ESI: %x [ESI]: %x\n", esi, [esi] @@: push edi xchg esi, edi movsd movsd movsd movsd movsd movsd movsd movsd pop edi ; lea esi, [esp+20] mov esi, [ebp+exFAT.LFN_reserve_place] mov word [esi+260*2], 0 ; force null-terminating for orphans jmp .no ;-------------------------------------- .longname: ; DEBUGF 1, "K : exFAT_get_name 0xC1\n" ; push ebp ; mov ebp,[esp+12+8+4+4+7*4+262*2+4+4] ; DEBUGF 1, "K : exFAT_get_name.longname 0 Input FS EBP:%x\n", ebp ; pop ebp ; DEBUGF 1, "K : exFAT_get_name.longname \n" ; DEBUGF 1, "K : exFAT_get_name.longname EDI:%x [EDI]:%x ESI:%x [ESI]:%x EBP:%x NAME:%s\n", edi, [edi], esi, [esi], ebp, ebp ; copy name (15 chars in UTF-16) ; mov word [esi+260*2], 0 ; force null-terminating for orphans ; push ebp ; mov ebp,[esp+12+8+4+4+7*4+262*2+4+4] ; DEBUGF 1, "K : exFAT_get_name.longname Input FS EBP:%x\n", ebp ; pop ebp call .save_curr_sector_number mov eax, [ebp+exFAT.hash_flag] test eax, eax jnz .no ; DEBUGF 1, "K : exFAT_get_name.longname hash match! \n" ; copy File Name Extension Directory Entry [0xC1] for calculate SetChecksum Field lea eax, [ebp+exFAT.fname_ext_dir_entry+32*17] cmp eax, [ebp+exFAT.fname_extdir_offset] je .no push edi esi xchg esi, edi mov edi, [ebp+exFAT.fname_extdir_offset] movsd movsd movsd movsd movsd movsd movsd movsd mov [ebp+exFAT.fname_extdir_offset], edi pop esi edi ; copy name push edi esi xchg esi, edi add esi, 2 movsd movsd movsd movsd movsd movsd movsd movsw ; force null-terminating for incomplete name xor eax, eax stosw pop esi edi ; push ebp ; mov ebp,[esp+12+8+4+4+7*4+262*2+4+4] ; DEBUGF 1, "K : exFAT_get_name.longname Output FS EBP:%x\n", ebp ; pop ebp mov eax, [ebp+exFAT.secondary_dir_entry] dec eax mov [ebp+exFAT.secondary_dir_entry], eax jz @f add esi, 30 ; DEBUGF 1, "K : exFAT_get_name 0xC1 CONT\n" jmp .no ; test ax, ax ; jnz .no ; if this is not first entry, more processing required @@: ; mov esi, [ebp+exFAT.LFN_reserve_place] ; DEBUGF 1, "K : exFAT_get_name.longname END \n" ; DEBUGF 1, "K : exFAT_get_name 0xC1 END\n" ret ;------------------------------------------------------------------------------ exFAT_entry_to_bdfe: ; DEBUGF 1, "K : exFAT_ReadFolder exFAT_entry_to_bdfe \n" ; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi mov eax, [ebp-4] mov [esi+4], eax ; cp866/UNICODE name exFAT_entry_to_bdfe2: ; movzx eax, byte [edi+11] movzx eax, byte [edi+4] mov [esi], eax ; attributes ; movzx eax, word [edi+14] movzx eax, word [edi+8] call fat_time_to_bdfe mov [esi+8], eax ; creation time ; movzx eax, word [edi+16] movzx eax, word [edi+8+2] 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+16] call fat_time_to_bdfe mov [esi+16], eax ; last access time ; movzx eax, word [edi+18] movzx eax, word [edi+16+2] call fat_date_to_bdfe mov [esi+20], eax ; last access date ; movzx eax, word [edi+22] movzx eax, word [edi+12] call fat_time_to_bdfe mov [esi+24], eax ; last write time ; movzx eax, word [edi+24] movzx eax, word [edi+12+2] call fat_date_to_bdfe mov [esi+28], eax ; last write date mov al, [esi] test al, 10000b jz .file_size xor eax, eax mov [esi+32], eax ; file size (low dword) mov [esi+36], eax ; file size (high dword) jmp @f .file_size: mov eax, [edi+32+8] mov [esi+32], eax ; file size (low dword) mov eax, [edi+32+8+4] mov [esi+36], eax ; file size (high dword) @@: test ebp, ebp jz .ret .copy_path: add esi, 40 push edi esi mov edi, esi mov esi, ebp cmp byte [ebp-4], 2 jz .utf16 cmp byte [ebp-4], 3 jz .utf8 @@: lodsw call uni2ansi_char stosb test al, al jnz @b pop esi edi add esi, 264 .ret: ; DEBUGF 1, "K : exFAT_entry_to_bdfe +264 ESI:%x\n", esi ret .utf8: push ecx mov ecx, 519 call UTF16to8_string pop ecx jmp @f .utf16: lodsw stosw test eax, eax jnz .utf16 @@: pop esi edi add esi, 520 ; DEBUGF 1, "K : exFAT_entry_to_bdfe +520 ESI:%x\n", esi ret ;------------------------------------------------------------------------------ exFAT_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] ; movzx eax, al ; DEBUGF 1, "K : bdfe file attributes: %x\n", eax and al, 0x27 ; and byte [edi+11], 0x10 ; or byte [edi+11], al and byte [edi+4], 0x10 or byte [edi+4], al ; movzx eax, byte [edi+4] ; DEBUGF 1, "K : exFAT file attributes: %x\n", eax ;@@: mov eax, [edx+8] ; DEBUGF 1, "K : bdfe creation time: %x\n", eax call bdfe_to_fat_time ; mov [edi+14], ax ; creation time mov [edi+8], ax ; creation time ; DEBUGF 1, "K : exFAT creation time: %x\n", ax mov eax, [edx+12] ; DEBUGF 1, "K : bdfe creation date: %x\n", eax call bdfe_to_fat_date ; mov [edi+16], ax ; creation date mov [edi+8+2], ax ; creation date ; DEBUGF 1, "K : exFAT creation date: %x\n", ax mov eax, [edx+16] ; DEBUGF 1, "K : bdfe access time: %x\n", eax call bdfe_to_fat_time mov [edi+16], ax ; last access time ; DEBUGF 1, "K : exFAT access time: %x\n", ax mov eax, [edx+20] ; DEBUGF 1, "K : bdfe access date: %x\n", eax call bdfe_to_fat_date ; mov [edi+18], ax ; last access date mov [edi+16+2], ax ; last access date ; DEBUGF 1, "K : exFAT access date: %x\n", ax mov eax, [edx+24] ; DEBUGF 1, "K : bdfe write time: %x\n", eax call bdfe_to_fat_time ; mov [edi+22], ax ; last write time mov [edi+12], ax ; last write time ; DEBUGF 1, "K : exFAT write time: %x\n", ax mov eax, [edx+28] ; DEBUGF 1, "K : bdfe write date: %x\n", eax call bdfe_to_fat_date ; mov [edi+24], ax ; last write date mov [edi+12+2], ax ; last write date ; DEBUGF 1, "K : exFAT write date: %x\n", ax ret ;------------------------------------------------------------------------------ exFAT_set_FAT: ; in: eax = cluster, edx = value to save ; out: edx = old value, CF=1 -> error push eax ebx esi cmp eax, 2 jc .ret cmp [ebp+exFAT.LAST_CLUSTER], eax jc .ret add eax, eax @@: add eax, eax mov esi, 511 and esi, eax shr eax, 9 add eax, [ebp+exFAT.FAT_START] mov ebx, [ebp+exFAT.fat_cache_ptr] cmp eax, [ebp+exFAT.fat_in_cache] je .inCache cmp [ebp+exFAT.fat_change], 0 je @f call exFAT_write_fat_sector @@: mov [ebp+exFAT.fat_in_cache], eax call fs_read32_sys test eax, eax jne .error .inCache: mov eax, [ebp+exFAT.fatMASK] 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 .write: mov [ebp+exFAT.fat_change], 1 and edx, [ebp+exFAT.fatMASK] .ret: pop esi ebx eax ret .error: stc jmp .ret ;------------------------------------------------------------------------------ exFAT_get_FAT: ; DEBUGF 1, "K : exFAT_get_FAT \n" ; in: eax = cluster ; out: eax = next cluster, CF=1 -> error push ebx esi ; cmp [ebp+FAT.fs_type], 12 ; je .FAT12 ; cmp [ebp+FAT.fs_type], 16 ; je @f ; add eax, eax ;@@: ; add eax, eax shl eax, 2 mov esi, 511 and esi, eax shr eax, 9 add eax, [ebp+exFAT.FAT_START] mov ebx, [ebp+exFAT.fat_cache_ptr] cmp eax, [ebp+exFAT.fat_in_cache] je .inCache cmp [ebp+exFAT.fat_change], 0 je @f call exFAT_write_fat_sector @@: mov [ebp+exFAT.fat_in_cache], eax call fs_read32_sys test eax, eax jnz .error .inCache: ; DEBUGF 1, "K : exFAT_get_FAT.inCache \n" mov eax, [ebx+esi] and eax, [ebp+exFAT.fatMASK] .ret: pop esi ebx ret .error: ; DEBUGF 1, "K : exFAT_get_FAT.error \n" stc jmp .ret ;------------------------------------------------------------------------------ exFAT_hd_find_lfn: ; DEBUGF 1, "K : exFAT_hd_find_lfn path ESI: %s\n", esi ; in: esi -> path string in UTF-8 ; out: CF=1 - file not found, eax=error code ; else CF=0 and edi->direntry, eax=sector push esi edi push 0 push 0 push exFAT_notroot_first ; 0 ; fat1x_root_first push exFAT_notroot_next ; 0 ; fat1x_root_next xor eax, eax mov [ebp+exFAT.General_Sec_Flags], eax mov dword [ebp+exFAT.valid_data_length], 0xffffffff ; for ROOT mov eax, [ebp+exFAT.ROOT_CLUSTER] ; mov [ebp+exFAT.secondary_dir_entry], dword 1 ; cmp [ebp+FAT.fs_type], 32 ; jz .fat32 jmp @f ; .fat32 .loop: and [ebp+exFAT.longname_sec1], 0 and [ebp+exFAT.longname_sec2], 0 ; push ebp ; mov ebp,[esp+12+8+4+4+7*4] ; DEBUGF 1, "K : exFAT_find_lfn Input FS EBP:%x\n", ebp ; pop ebp call exFAT_find_lfn ; push ebp ; mov ebp,[esp+12+8+4+4+7*4] ; DEBUGF 1, "K : exFAT_find_lfn Output FS EBP:%x\n", ebp ; pop ebp jc .notfound ; DEBUGF 1, "K : exFAT_hd_find_lfn [ESI]: %x\n", [esi] cmp byte [esi], 0 jz .found ; test byte [edi+11], 10h push eax lea eax, [ebp+exFAT.file_dir_entry] ; DEBUGF 1, "K : exFAT_hd_find_lfn exFAT.file_dir_entry [EAX]: %x\n", [eax] test byte [eax+4], 10000b pop eax jz .notfound and dword [esp+12], 0 ; this entry’s first cluster number ; mov eax, [edi+20-2] ; mov ax, [edi+26] ; cluster lea eax, [ebp+exFAT.str_ext_dir_entry] push eax movzx eax, byte [eax+1] mov [ebp+exFAT.General_Sec_Flags], eax ; DEBUGF 1, "K : exFAT General_Sec_Flags %x\n", eax mov eax, [esp] mov eax, [eax+8] ; LOW dword of Valid data length - WARNING!!! late rewrite mov [ebp+exFAT.valid_data_length], eax ; DEBUGF 1, "K : exFAT.valid_data_length 1 %x\n", eax pop eax mov eax, [eax+20] ; cluster ;.fat32: @@: ; DEBUGF 1, "K : exFAT_hd_find_lfn exFAT cluster EAX: %x\n", eax mov [esp+8], eax ; mov dword [esp+4], exFAT_notroot_first ; fat_notroot_first ; mov dword [esp], exFAT_notroot_next ; fat_notroot_next jmp .loop .notfound: ; DEBUGF 1, "K : exFAT_hd_find_lfn.notfound EAX:%x\n", eax add esp, 16 pop edi esi stc ret .found: ; DEBUGF 1, "K : exFAT_hd_find_lfn.found \n" lea eax, [esp+8] cmp dword [eax], 0 jz .root call exFAT_get_sector jmp .cmn .root: ; DEBUGF 1, "K : exFAT_hd_find_lfn.found.root \n" mov eax, [eax+4] add eax, [ebp+exFAT.ROOT_START] .cmn: ; DEBUGF 1, "K : exFAT_hd_find_lfn.found.cmn \n" add esp, 20 ; CF=0 pop esi ret ;------------------------------------------------------------------------------ exFAT_find_lfn: ; DEBUGF 1, "K : exFAT_find_lfn \n" ; in: ; esi -> path in UTF-8 ; parameters in the stack ; out: ; esi -> next name in the path ; edi -> direntry ; CF=1 -> file not found, eax = error code xor eax, eax inc eax mov [ebp+exFAT.secondary_dir_entry], eax ; dword 1 mov [ebp+exFAT.need_hash], eax ; dword 1 lea eax, [esp+12] call dword [eax-4] ; exFAT_notroot_first jc .reterr sub esp, 262*2 ; reserve place for LFN ; lea eax, [esp] mov eax, esp mov [ebp+exFAT.LFN_reserve_place], eax mov [ebp+exFAT.path_in_UTF8], esi ; DEBUGF 1, "K : exFAT_find_lfn Path: %s\n", esi ; DEBUGF 1, "K : exFAT Path: %s\n", esi ; DEBUGF 1, "K : exFAT Path1: %x %x %x\n", [esi], [esi+4], [esi+8] push esi edi ; lea edi, [esp+8] mov edi, eax align 4 @@: ; in: esi -> UTF-8 char (increasing) ; out: ax = UTF-16 char call utf8to16 call utf16toUpper stosw test ax, ax jz @f cmp ax, word 0x002f ; "/" jne @b @@: ; mov [edi-2], dword 0 mov esi, [ebp+exFAT.LFN_reserve_place] ; DEBUGF 1, "K : exFAT Path2: %x %x %x\n", [esi], [esi+4], [esi+8] push ebx ecx mov ecx, edi sub ecx, esi sub ecx, 2 ; correction for zero or "/" ; exFAT_hash_calculate ; in: ; esi -> NameUTF16 ; ecx -> NameUTF16 length ; out: ax = hash xor eax, eax xor ebx, ebx ;-------------------------------------- align 4 .start: ; DEBUGF 1, "Hash start EAX:%x ECX:%x\n", eax, ecx mov bx, ax ; (Hash&1) ? 0x8000 : 0) and ax, 0x1 jz .else mov ax, 0x8000 jmp @f ;-------------------------------------- .else: xor ax, ax ;-------------------------------------- @@: ; DEBUGF 1, "(Hash&1) EAX:%x\n", eax ; (Hash>>1) shr bx, 1 ; DEBUGF 1, "(Hash>>1) EBX:%x\n", ebx add ax, bx ; DEBUGF 1, "+ (Hash>>1)) EAX:%x\n", eax movzx bx, byte [esi] add ax, bx ; DEBUGF 1, "+ (UInt16)Buffer[Index] EAX:%x\n", eax inc esi dec ecx jnz .start ;-------------------------------------- pop ecx ebx mov [ebp+exFAT.current_hash], eax ; DEBUGF 1, "K : exFAT current hash :%x\n", eax pop edi esi .l1: ; push esi ; lea esi, [esp+4] ; mov esi, [ebp+exFAT.LFN_reserve_place] ; DEBUGF 1, "K : exFAT_find_lfn.exFAT_get_name \n" ; push ebp ; mov ebp,[esp+12+8+4+4+7*4+262*2+4] ; DEBUGF 1, "K : exFAT_get_name Input FS EBP:%x\n", ebp ; pop ebp ; DEBUGF 1, "K : exFAT FL need_hash :%x\n", [ebp+exFAT.need_hash] call exFAT_get_name ; mov [ebp+exFAT.LFN_reserve_place], esi ; pop esi ; push ebp ; mov ebp,[esp+12+8+4+4+7*4+262*2+4] ; DEBUGF 1, "K : exFAT_get_name Output FS EBP:%x\n", ebp ; pop ebp jc .no ; push eax xor eax, eax cmp [ebp+exFAT.secondary_dir_entry], eax ; pop eax jnz .no push edi esi mov esi, [ebp+exFAT.path_in_UTF8] lea edi, [esp+8] @@: call utf8to16 call utf16toUpper mov edx, eax mov ax, [edi] call utf16toUpper cmp ax, dx jnz .done add edi, 2 test ax, ax jnz @b dec esi pop eax edi .found: ; DEBUGF 1, "K : exFAT_find_lfn.found \n" add esp, 262*2 ; if this is LFN entry, advance to true entry ; cmp byte [edi+11], 0xF ; jnz @f xor eax, eax cmp [ebp+exFAT.secondary_dir_entry], eax jz @f lea eax, [esp+12] call dword[eax-8] ; exFAT_notroot_next jc .reterr @@: ; DEBUGF 1, "K : exFAT_find_lfn.OK \n" xor eax, eax ret .done: ; DEBUGF 1, "K : exFAT_find_lfn.done \n" cmp dx, '/' jnz @f test ax, ax jnz @f mov [esp], esi @@: pop esi edi jz .found .no: ; DEBUGF 1, "K : exFAT_find_lfn.no \n" lea eax, [esp+262*2+12] ; DEBUGF 1, "K : exFAT General_Sec_Flags %x\n", [ebp+exFAT.General_Sec_Flags] ; DEBUGF 1, "K : exFAT.valid_data_length 2 %x\n", [ebp+exFAT.valid_data_length] cmp [ebp+exFAT.valid_data_length], 0 jbe .error ; DEBUGF 1, "K : exFAT_find_lfn call dword[eax-8] ; exFAT_notroot_next: \n" call dword[eax-8] ; exFAT_notroot_next jnc .l1 @@: ; DEBUGF 1, "K : exFAT_find_lfn.@@: \n" add esp, 262*2 .reterr: ; DEBUGF 1, "K : exFAT_find_lfn.reterr \n" stc ret .error: movi eax, ERROR_FILE_NOT_FOUND jmp @b ;------------------------------------------------------------------------------ exFAT_ReadFile: ; DEBUGF 1, "K : exFAT_ReadFile \n" ; DEBUGF 1, "K : exFAT F70 +00: %x\n", [ebx] ; DEBUGF 1, "K : exFAT F70 +04: %x\n", [ebx+4] ; DEBUGF 1, "K : exFAT F70 +08: %x\n", [ebx+8] ; DEBUGF 1, "K : exFAT F70 +12: %x\n", [ebx+12] ; DEBUGF 1, "K : exFAT F70 +16: %x\n", [ebx+16] ; DEBUGF 1, "K : exFAT F70 +20: %x\n", [ebx+20] ; DEBUGF 1, "K : exFAT Path: %s\n", esi ; push eax ; pushfd ; pop eax ; DEBUGF 1, "K : eFlags:%x\n",eax ; pop eax ; DEBUGF 1, "K : EAX:%x EBX:%x ECX:%x EDX:%x\n", eax, ebx, ecx, edx ; DEBUGF 1, "K : EBP:%x ESI:%x EDI:%x\n", ebp, esi, edi ; in: ; ebx -> parameter structure of sysfunc 70 ; ebp -> exFAT structure ; esi -> path string in UTF-8 ; out: ; eax, ebx = return values for sysfunc 70 call exFAT_lock xor eax, eax mov [ebp+exFAT.need_hash], eax ; dword 0 mov [ebp+exFAT.hash_flag], eax ; dword 0 call exFAT_hd_find_lfn jc .notFound ; test byte [edi+11], 0x10 ; do not allow read directories ; jnz .noaccess lea eax, [ebp+exFAT.file_dir_entry] test byte [eax+4], 10000b ; do not allow read directories jnz .noaccess ; Rewrite code to work with more than 4 GB files !!! ; cmp dword [ebx+8], 0 ; jnz .endOfFile mov edx, [ebx+8] ; file offset high ; DEBUGF 1, "K : exFAT_ReadFile Hdword file offset EDX:%x\n", edx mov [ebp+exFAT.RDX_high], edx mov edx, [ebx+4] ; file offset low ; DEBUGF 1, "K : exFAT_ReadFile Ldword file offset EAX:%x\n", edx mov ecx, [ebx+12] ; size mov ebx, [ebx+16] ; buffer push ebx push 0 test ecx, ecx ; read size 0? jz .done ; mov eax, [edi+28] ; real file size lea eax, [ebp+exFAT.str_ext_dir_entry] ; DEBUGF 1, "K : exFAT 0xC0 +00: %x\n", [eax] ; DEBUGF 1, "K : exFAT 0xC0 +04: %x\n", [eax+4] ; DEBUGF 1, "K : exFAT 0xC0 +08: %x\n", [eax+8] ; DEBUGF 1, "K : exFAT 0xC0 +12: %x\n", [eax+12] ; DEBUGF 1, "K : exFAT 0xC0 +16: %x\n", [eax+16] ; DEBUGF 1, "K : exFAT 0xC0 +20: %x\n", [eax+20] ; DEBUGF 1, "K : exFAT 0xC0 +24: %x\n", [eax+24] ; DEBUGF 1, "K : exFAT 0xC0 +28: %x\n", [eax+28] push eax movzx eax, byte [eax+1] mov [ebp+exFAT.General_Sec_Flags], eax pop eax push eax mov eax, [eax+12] ; high dword of real file size mov [ebp+exFAT.RAX_high], eax ; DEBUGF 1, "K : exFAT_ReadFile Hdword file size EAX:%x\n", eax pop eax mov eax, [eax+8] ; low dword of real file size ; DEBUGF 1, "K : exFAT_ReadFile Ldword file size EAX:%x\n", eax ; sub eax, edx ; low dword file size - file offset low = rest of file ; jb .fileEnd sub eax, edx ; low dword file size - file offset low = rest of file push eax mov eax, [ebp+exFAT.RDX_high] sbb [ebp+exFAT.RAX_high], eax pop eax jb .fileEnd ; DEBUGF 1, "K : exFAT_ReadFile Hdword rest of file RAX:%x\n", [ebp+exFAT.RAX_high] ; DEBUGF 1, "K : exFAT_ReadFile Ldword rest of file EAX:%x\n", eax push eax mov eax, [ebp+exFAT.RAX_high] test eax, eax pop eax jnz @f cmp eax, ecx ; rest of file - requested size jae @f ; DEBUGF 1, "K : exFAT_ReadFile 6=EOF EAX:%x ECX:%x EDX:%x\n", eax, ecx, edx mov ecx, eax mov byte [esp], 6 ; 6 = end of file, EOF @@: lea eax, [ebp+exFAT.str_ext_dir_entry] mov eax, [eax+20] ; cluster ; DEBUGF 1, "K : exFAT EAX:%x EBX:%x ECX:%x EDX:%x\n", eax, ebx, ecx, edx ; now eax=cluster, ebx=buffer for data, ecx=count, edx=position mov edi, [ebp+exFAT.SECTORS_PER_CLUSTER] shl edi, 9 ; bytes per cluster @@: cmp eax, 2 jb .fileEnd .continue_1: cmp eax, [ebp+exFAT.fatRESERVED] jae .fileEnd push eax xor eax, eax sub edx, edi ; file_offset_low - bytes per cluster sbb [ebp+exFAT.RDX_high], eax pop eax jc @f ; push edi ; lea edi, [ebp+exFAT.file_dir_entry] ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved ; test byte [edi+1], 11b ; pop edi test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT_1 inc eax jmp .continue_1 .get_FAT_1: call exFAT_get_FAT jc .noaccess2 jmp @b .notFound: ; DEBUGF 1, "K : exFAT_ReadFile.notFound: \n" push eax jmp .ret .noaccess: ; DEBUGF 1, "K : exFAT_ReadFile.noaccess \n" push ERROR_ACCESS_DENIED jmp .ret .endOfFile: ; DEBUGF 1, "K : exFAT_ReadFile.endOfFile \n" push ERROR_END_OF_FILE .ret: call exFAT_unlock pop eax xor ebx, ebx ; DEBUGF 1, "K : exFAT_ReadFile Return EBX:%x\n", ebx ret @@: ; DEBUGF 1, "K : exFAT_ReadFile CONTINUE cluster EAX:%x\n", eax mov esi, eax dec eax dec eax push ebx edx xor edx, edx ; DEBUGF 1, "K : exFAT_ReadFile IMUL in EDX:%x EAX:%x\n", EDX, eax imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] ; Sector edx:eax ; DEBUGF 1, "K : exFAT_ReadFile IMUL out EDX:%x EAX:%x\n", EDX, eax xor ebx, ebx add eax, [ebp+exFAT.CLUSTER_HEAP_START] adc edx, ebx mov [ebp+exFAT.RAX_high], edx pop edx ebx ; DEBUGF 1, "K : exFAT_ReadFile start sector RAX_H:%x EAX:%x RDX_H:%x EDX:%x EDI:%x\n", [ebp+exFAT.RAX_high], eax, [ebp+exFAT.RDX_high], edx, edi push eax xor eax, eax add edx, edi ; file offset low + bytes per cluster adc [ebp+exFAT.RDX_high], eax pop eax test edx, edx jz .alignedCluster mov edi, edx ; file offset low push eax mov eax, [ebp+exFAT.RDX_high] mov [ebp+exFAT.RDI_high], eax pop eax ; shr edi, 9 push ebx mov ebx, [ebp+exFAT.RDI_high] shrd edi, ebx, 5 ; /32 shr ebx, 5 ; /32 shrd edi, ebx, 4 ; /16 shr ebx, 4 ; /16 mov [ebp+exFAT.RDI_high], ebx pop ebx add eax, edi ; RFile_start_sector_low - file_sector_offset_low push ebx mov ebx, [ebp+exFAT.RDI_high] adc [ebp+exFAT.RAX_high], ebx pop ebx and edx, 511 and dword [ebp+exFAT.RDX_high], 0 cmp ecx, 512 jc .sectorPiece test edx, edx jz .alignedSector .sectorPiece: ; DEBUGF 1, "K : exFAT_ReadFile.sectorPiece \n" push eax ebx ecx edx lea ebx, [ebp+exFAT.buffer] mov edx, [ebp+exFAT.RAX_high] xor ecx, ecx inc ecx ; DEBUGF 1, "K : exFAT fs_read64_app EDX:%x EAX:%x ECX:%x EBX:%x EBP:%x\n", edx, eax, ecx, ebx, ebp ; call fs_read32_app call fs_read64_app ; DEBUGF 1, "K : exFAT fs_read64_app Output EAX:%x ECX:%x EBX:%x\n", eax, ecx, ebx test eax, eax ; lea eax, [ebp+exFAT.buffer] mov eax, ebx ; exFAT.buffer pop edx ecx ebx jne .noaccess3 ; DEBUGF 1, "K : exFAT_ReadFile memmove(-1) EAX:%x EBX:%x ECX:%x EDX:%x\n", eax, ebx, ecx, edx add eax, edx ; exFAT.buffer + offset within a sector push ecx add ecx, edx ; requested size + offset within a sector cmp ecx, 512 jbe @f mov ecx, 512 @@: sub ecx, edx ; requested size - offset within a sector ; DEBUGF 1, "K : exFAT_ReadFile memmove EAX:%x EBX:%x ECX:%x\n", eax, ebx, ecx ; eax = from ; ebx = to ; ecx = no of bytes call memmove ; DEBUGF 1, "K : exFAT_ReadFile memmove(1) EAX:%x EBX:%x ECX:%x\n", eax, ebx, ecx sub [esp], ecx add ebx, ecx ; DEBUGF 1, "K : exFAT_ReadFile memmove(2) EAX:%x EBX:%x ECX:%x\n", eax, ebx, ecx pop ecx eax xor edx, edx ; inc edi ; file_sector_offset_low push eax xor eax, eax add edi, 1 ; you cannot use INC EDI for qword!!! adc [ebp+exFAT.RDI_high], eax pop eax ; inc eax ; RFile_start_sector_low push ebx xor ebx, ebx add eax, 1 ; you cannot use INC EAX for qword!!! adc [ebp+exFAT.RAX_high], ebx pop ebx test ecx, ecx jz .done .alignedSector: ; DEBUGF 1, "K : exFAT_ReadFile.alignedSector \n" ; shl edi, 9 ; RFile_start_sector_low * 512 push ebx mov ebx, [ebp+exFAT.RDI_high] shld ebx, edi, 5 ; *32 shl edi, 5 ; *32 shld ebx, edi, 4 ; *16 shl edi, 4 ; *16 mov [ebp+exFAT.RDI_high], ebx pop ebx push ebx xor ebx, ebx mov [ebp+exFAT.RCX_high], ebx add ecx, edi ; requested size + file_offset_low mov ebx, [ebp+exFAT.RDI_high] adc [ebp+exFAT.RCX_high], ebx pop ebx xor edi, edi mov [ebp+exFAT.RDI_high], edi mov edi, [ebp+exFAT.SECTORS_PER_CLUSTER] shl edi, 9 ; bytes per cluster .alignedCluster: ; DEBUGF 1, "K : exFAT_ReadFile.alignedCluster RAX_H:%x EAX:%x RDX_H:%x EDX:%x EDI:%x\n", [ebp+exFAT.RAX_high], eax, [ebp+exFAT.RDX_high], edx, edi cmp ecx, 512 jc .sectorPiece mov edx, [ebp+exFAT.RAX_high] mov [ebp+exFAT.RDX_high], edx mov edx, eax ; edx << RFile_start_sector_low xor eax, eax mov [ebp+exFAT.RAX_high], eax mov eax, esi ; eax << cluster @@: push eax xor eax, eax sub ecx, edi ; requested size low - bytes per cluster sbb [ebp+exFAT.RCX_high], eax pop eax jbe .readEnd ; push edi ; lea edi, [ebp+exFAT.file_dir_entry] ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved ; test byte [edi+1], 11b ; pop edi test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT inc eax ; inc cluster jmp .continue .get_FAT: ; DEBUGF 1, "K : exFAT_ReadFile.get_FAT \n" call exFAT_get_FAT jc .noaccess4 cmp eax, 2 jb .fileEnd2 .continue: ; DEBUGF 1, "K : exFAT_ReadFile.continue \n" cmp eax, [ebp+exFAT.fatRESERVED] jae .fileEnd2 inc esi ; inc cluster cmp eax, esi jz @b .fragmentEnd: ; DEBUGF 1, "K : exFAT_ReadFile.fragmentEnd \n" xchg eax, esi dec eax dec eax push ebx edx xor edx, edx imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] ; Sector edx:eax xor ebx, ebx add eax, [ebp+exFAT.CLUSTER_HEAP_START] adc edx, ebx mov [ebp+exFAT.RAX_high], edx pop edx ebx push dword [ebp+exFAT.RCX_high] push ecx ; requested size low mov ecx, [ebp+exFAT.RAX_high] mov [ebp+exFAT.RCX_high], ecx mov ecx, eax ; ecx << RFile_start_sector_low xor eax, eax mov [ebp+exFAT.RAX_high], eax mov eax, esi ; eax << custer dec eax dec eax push ebx edx xor edx, edx imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] ; Sector edx:eax xor ebx, ebx add eax, [ebp+exFAT.CLUSTER_HEAP_START] adc edx, ebx mov [ebp+exFAT.RAX_high], edx pop edx ebx push dword [ebp+exFAT.RAX_high] push eax .readFragment: ; DEBUGF 1, "K : exFAT_ReadFile.readFragment \n" push eax mov eax, [ebp+exFAT.RDX_high] sub ecx, edx ; RFile_start_sector_low - RFile_start_sector_low sbb [ebp+exFAT.RCX_high], eax pop eax mov eax, edx ; xor edx, edx mov edx, [ebp+exFAT.RDX_high] ; DEBUGF 1, "K : exFAT fs_read64_app EDX:%x EAX:%x ECX:%x EBX:%x EBP:%x\n", edx, eax, ecx, ebx, ebp call fs_read64_app ; DEBUGF 1, "K : exFAT fs_read64_app Output EAX:%x ECX:%x EBX:%x\n", eax, ecx, ebx ; shl ecx, 9 push ebx mov ebx, [ebp+exFAT.RCX_high] shld ebx, ecx, 5 ; *32 shl ecx, 5 ; *32 shld ebx, ecx, 4 ; *16 shl ecx, 4 ; *16 mov [ebp+exFAT.RCX_high], ebx pop ebx add ebx, ecx test eax, eax pop eax pop dword [ebp+exFAT.RAX_high] jnz .noaccess3 pop ecx pop dword [ebp+exFAT.RCX_high] xor edx, edx mov [ebp+exFAT.RDX_high], edx jecxz .done_1 jmp .alignedCluster .done_1: jmp .done .readEnd: ; DEBUGF 1, "K : exFAT_ReadFile.readEnd \n" push ebx add ecx, edi ; requested size + bytes per cluster mov ebx, [ebp+exFAT.RDI_high] adc [ebp+exFAT.RCX_high], ebx pop ebx mov edi, [ebp+exFAT.RCX_high] mov [ebp+exFAT.RDI_high], edi mov edi, ecx and ecx, 511 and dword [ebp+exFAT.RCX_high], 0 ; shr edi, 9 push ebx mov ebx, [ebp+exFAT.RDI_high] shrd edi, ebx, 5 ; /32 shr ebx, 5 ; /32 shrd edi, ebx, 4 ; /16 shr ebx, 4 ; /16 mov [ebp+exFAT.RDI_high], ebx pop ebx dec eax dec eax push ebx edx xor edx, edx imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] ; Sector edx:eax xor ebx, ebx add eax, [ebp+exFAT.CLUSTER_HEAP_START] adc edx, ebx mov [ebp+exFAT.RAX_high], edx pop edx ebx add eax, edi ; RFile_start_sector_low - file_sector_offset_low push ebx mov ebx, [ebp+exFAT.RDI_high] adc [ebp+exFAT.RAX_high], ebx pop ebx push dword [ebp+exFAT.RCX_high] push ecx push dword [ebp+exFAT.RAX_high] push eax mov ecx, [ebp+exFAT.RAX_high] mov [ebp+exFAT.RCX_high], ecx mov ecx, eax jmp .readFragment .noaccess3: ; DEBUGF 1, "K : exFAT_ReadFile.noaccess3 \n" pop eax pop dword [ebp+exFAT.RAX_high] .noaccess2: ; DEBUGF 1, "K : exFAT_ReadFile.noaccess2 \n" mov byte [esp], ERROR_DEVICE .done: ; DEBUGF 1, "K : exFAT_ReadFile.done \n" call exFAT_unlock pop eax edx sub ebx, edx ; DEBUGF 1, "K : exFAT_ReadFile Return EBX:%x\n", ebx ; push eax ; pushfd ; pop eax ; DEBUGF 1, "K : eFlags:%x\n",eax ; pop eax ; DEBUGF 1, "K : EAX:%x EBX:%x ECX:%x EDX:%x\n", eax, ebx, ecx, edx ; DEBUGF 1, "K : EBP:%x ESI:%x EDI:%x\n", ebp, esi, edi ret .fileEnd: ; DEBUGF 1, "K : exFAT_ReadFile.fileEnd \n" mov byte [esp], ERROR_END_OF_FILE jmp .done .noaccess4: ; DEBUGF 1, "K : exFAT_ReadFile.noaccess4 \n" mov byte [esp], ERROR_DEVICE jmp @f .fileEnd2: ; DEBUGF 1, "K : exFAT_ReadFile.fileEnd2 \n" mov byte [esp], ERROR_END_OF_FILE @@: inc esi xor ecx, ecx mov [ebp+exFAT.RCX_high], ecx jmp .fragmentEnd ;------------------------------------------------------------------------------ exFAT_ReadFolder: ; DEBUGF 1, "K : exFAT_ReadFolder \n" ; DEBUGF 1, "K : exFAT F70 +00: %x\n", [ebx] ; DEBUGF 1, "K : exFAT F70 +04: %x\n", [ebx+4] ; DEBUGF 1, "K : exFAT F70 +08: %x\n", [ebx+8] ; DEBUGF 1, "K : exFAT F70 +12: %x\n", [ebx+12] ; DEBUGF 1, "K : exFAT F70 +16: %x\n", [ebx+16] ; DEBUGF 1, "K : exFAT F70 +20: %x\n", [ebx+20] ; DEBUGF 1, "K : exFAT Path: %s\n", esi ; push eax ; pushfd ; pop eax ; DEBUGF 1, "K : eFlags:%x\n",eax ; pop eax ; DEBUGF 1, "K : EAX:%x EBX:%x ECX:%x EDX:%x\n", eax, ebx, ecx, edx ; DEBUGF 1, "K : EBP:%x ESI:%x EDI:%x\n", ebp, esi, edi ; in: ; ebx -> parameter structure of sysfunc 70 ; ebp -> exFAT structure ; esi -> path string in UTF-8 ; out: ; eax, ebx = return values for sysfunc 70 call exFAT_lock xor eax, eax mov [ebp+exFAT.need_hash], eax ; dword 0 mov [ebp+exFAT.hash_flag], eax ; dword 0 mov [ebp+exFAT.General_Sec_Flags], eax ; DEBUGF 1, "K : exFAT_ReadFolder General_Sec_Flags 1 %x\n", eax mov eax, [ebp+exFAT.ROOT_CLUSTER] ; DEBUGF 1, "K : exFAT.ROOT_CLUSTER: %x\n", eax cmp byte [esi], 0 jz .doit ; push ebp ; mov ebp,[esp+12+8+4+4] ; DEBUGF 1, "K : exFAT Input FS EBP:%x\n", ebp ; pop ebp call exFAT_hd_find_lfn ; push ebp ; mov ebp,[esp+12+8+4+4] ; DEBUGF 1, "K : exFAT Output FS EBP:%x\n", ebp ; pop ebp jc .error ; jmp .error ; test byte [edi+11], 0x10 ; do not allow read files ; jz .accessDenied xor eax, eax mov [ebp+exFAT.need_hash], eax ; dword 0 mov [ebp+exFAT.hash_flag], eax ; dword 0 lea eax, [ebp+exFAT.file_dir_entry] test byte [eax+4], 10000b ; do not allow read files jz .accessDenied ; mov eax, [edi+20-2] ; mov ax, [edi+26] ; eax=cluster lea eax, [ebp+exFAT.str_ext_dir_entry] push eax movzx eax, byte [eax+1] mov [ebp+exFAT.General_Sec_Flags], eax ; DEBUGF 1, "K : exFAT_ReadFolder General_Sec_Flags 2 %x\n", eax mov eax, [esp] mov eax, [eax+8] ; LOW dword of Valid data length - WARNING!!! late rewrite mov [ebp+exFAT.valid_data_length], eax pop eax mov eax, [eax+20] ; cluster jmp .doit_1 .doit: mov dword [ebp+exFAT.valid_data_length], 0xffffffff ; for ROOT .doit_1: ; DEBUGF 1, "K : exFAT.valid_data_length %x\n", [ebp+exFAT.valid_data_length] ; DEBUGF 1, "K : exFAT_ReadFolder.doit \n" sub esp, 262*2 ; reserve space for LFN push dword [ebx+8] ; cp866/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 [ebp+exFAT.points_to_BDFE], edi ; DEBUGF 1, "K : exFAT.points_to_BDFE start EDI: %x\n", edi mov ecx, [ebx+12] ; number of blocks to read mov ebx, [ebx+4] ; index of the first block ;------------------------------------------------------------------------------ ; DEBUGF 1, "K : exFAT_ReadFolder 1 ECX: %x\n", ecx cmp [ebp+exFAT.valid_data_length], 0xffffffff je .num_read_blocks inc dword [edx+8] ; new file found test ecx, ecx jz .num_read_blocks test ebx, ebx jnz .dec_offset ; DEBUGF 1, "K : exFAT_ReadFolder create .. dir \n" inc dword [edx+4] ; new file block copied push eax esi mov esi, edi ; [ebp+exFAT.points_to_BDFE] mov [esi], dword 0x10 ; attributes xor eax, eax mov [esi+8], eax ; creation time mov [esi+12], dword 0x010101 ; eax ; creation date mov [esi+16], eax ; last access time mov [esi+20], dword 0x020202 ;eax ; last access date mov [esi+24], eax ; last write time mov [esi+28], dword 0x010303 ; eax ; last write date mov [esi+32], eax ; file size (low dword) mov [esi+36], eax ; file size (high dword) push ebp lea ebp, [esp+4+12] ; DEBUGF 1, "K : exFAT_ReadFolder 1 ESI: %x EBP: %x\n", esi, ebp ; DEBUGF 1, "K : exFAT_ReadFolder old file [EBP-4]: %x [EBP]: %x [EBP+4]: %x [EBP+8]: %x\n", [ebp-4], [ebp], [ebp+4], [ebp+8] mov eax, [ebp-4] mov [esi+4], eax ; cp866/UNICODE name mov [ebp], dword 0x002e002e ; imitate dir '..' xor eax, eax mov [ebp+4], eax call exFAT_entry_to_bdfe2.copy_path pop ebp mov [ebp+exFAT.points_to_BDFE], esi ; DEBUGF 1, "K : exFAT_ReadFolder 2 ESI: %x EBP: %x\n", esi, ebp pop esi eax dec ecx jmp .num_read_blocks .dec_offset: dec ebx .num_read_blocks: ; DEBUGF 1, "K : exFAT_ReadFolder 2 ECX: %x\n", ecx ;------------------------------------------------------------------------------ lea esi, [esp+4] ; buffer for UTF-16 name (space for LFN) mov [ebp+exFAT.LFN_reserve_place], esi ; push eax ; dec eax ; dec eax ; imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] ; add eax, [ebp+exFAT.CLUSTER_HEAP_START] ; DEBUGF 1, "K : exFAT ROOT SECTOR: %x\n", eax ; pop eax mov [ebp+exFAT.secondary_dir_entry], dword 1 .new_cluster: ; DEBUGF 1, "K : exFAT_ReadFolder.new_cluster \n" mov [ebp+exFAT.cluster_tmp], eax test eax, eax ; jz .notfound jnz @f jmp .notfound @@: dec eax dec eax imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] push [ebp+exFAT.SECTORS_PER_CLUSTER] add eax, [ebp+exFAT.CLUSTER_HEAP_START] push ebx .new_sector: ; DEBUGF 1, "K : exFAT_ReadFolder.new_sector \n" lea ebx, [ebp+exFAT.buffer] mov edi, ebx push eax ; DEBUGF 1, "K : exFAT fs_read32_sys N1 EAX: %x\n", eax call fs_read32_sys test eax, eax pop eax jnz .notfound2 add ebx, 512 push eax .l1: ; cmp [edi], dword 0 ; je .l1_1 ; DEBUGF 1, "K : exFAT_ReadFolder.l1 [EDI]:%x\n", [edi] ;.l1_1: ; push esi ; lea esi, [esp+20] ; DEBUGF 1, "K : exFAT RD need_hash :%x\n", [ebp+exFAT.need_hash] call exFAT_get_name ; pop esi jc .l2 ; cmp byte [edi], 0xC1 ; File Name Extension Directory Entry of ExFAT ; jnz .do_bdfe ; DEBUGF 1, "K : exFAT_ReadFolder CMP SDE\n" xor eax, eax cmp [ebp+exFAT.secondary_dir_entry], eax jz .do_bdfe ; add edi, 0x20 ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe EDI: %x EBX: %x\n", edi, ebx ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe EDI:%x [EDI]:%x NAME:%s\n", edi, [edi], edi cmp edi, ebx jb .do_bdfe ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe EDI after\n", edi, ebx pop eax inc eax dec dword [esp+4] jnz @f mov eax, [ebp+exFAT.cluster_tmp] test eax, eax jz .done ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT_1 inc eax jmp .continue_1 .get_FAT_1: ; DEBUGF 1, "K : exFAT_ReadFolder N1 exFAT_get_FAT Input EAX: %x\n", eax call exFAT_get_FAT ; DEBUGF 1, "K : exFAT_ReadFolder N1 exFAT_get_FAT Output EAX: %x\n", eax jc .notfound2 cmp eax, 2 jb .done .continue_1: ; DEBUGF 1, "K : exFAT_ReadFolder.continue_1\n" cmp eax, [ebp+exFAT.fatRESERVED] jae .done push eax mov eax, [ebp+exFAT.SECTORS_PER_CLUSTER] mov [esp+8], eax pop eax mov [ebp+exFAT.cluster_tmp], eax dec eax dec eax imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] add eax, [ebp+exFAT.DATA_START] @@: ; DEBUGF 1, "K : exFAT_ReadFolder.@@ \n" lea ebx, [ebp+exFAT.buffer] mov edi, ebx push eax ; DEBUGF 1, "K : exFAT fs_read32_sys N2 EAX: %x\n", eax call fs_read32_sys test eax, eax pop eax jnz .notfound2 add ebx, 512 push eax .do_bdfe: ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe \n" inc dword [edx+8] ; new file found dec dword [esp+4] jns .l2 ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe ECX: %x\n", ecx dec ecx js .l2 ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe 2 \n" inc dword [edx+4] ; new file block copied push esi edi mov esi, [ebp+exFAT.points_to_BDFE] lea edi, [ebp+exFAT.file_dir_entry] push ebp lea ebp, [esp+20+4+4] ; DEBUGF 1, "K : exFAT_ReadFolder ESI: %x EBP: %x\n", esi, ebp ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe EDI:%x [EDI]:%x ESI:%x [ESI]:%x EBP:%x NAME:%s\n", edi, [edi], esi, [esi], ebp, ebp call exFAT_entry_to_bdfe pop ebp mov [ebp+exFAT.points_to_BDFE], esi pop edi esi .l2: ; DEBUGF 1, "K : exFAT_ReadFolder.l2 \n" add edi, 0x20 ; DEBUGF 1, "K : exFAT_ReadFolder.do_bdfe EDI: %x EBX: %x\n", edi, ebx cmp edi, ebx jb .l1 pop eax inc eax dec dword [esp+4] jnz .new_sector mov eax, [ebp+exFAT.cluster_tmp] test eax, eax jz .done push eax mov eax, [ebp+exFAT.SECTORS_PER_CLUSTER] shl eax, 9 sub [ebp+exFAT.valid_data_length], eax pop eax jbe .done ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT inc eax jmp .continue .get_FAT: ; DEBUGF 1, "K : exFAT_ReadFolder N2 exFAT_get_FAT Input EAX: %x\n", eax call exFAT_get_FAT ; DEBUGF 1, "K : exFAT_ReadFolder N2 exFAT_get_FAT Output EAX: %x\n", eax jc .notfound2 cmp eax, 2 jb .done .continue: ; DEBUGF 1, "K : exFAT_ReadFolder.continue \n" cmp eax, [ebp+exFAT.fatRESERVED] jae .done ; DEBUGF 1, "K : exFAT_ReadFolder.continue after\n" push eax mov eax, [ebp+exFAT.SECTORS_PER_CLUSTER] mov [esp+8], eax pop eax pop ebx add esp, 4 jmp .new_cluster ;------------------------------------------------------------------------------ .notfound2: ; DEBUGF 1, "K : exFAT_ReadFolder.notfound2 \n" add esp, 8 .notfound: ; DEBUGF 1, "K : exFAT_ReadFolder.notfound \n" add esp, 262*2+4 ; DEBUGF 1, "K : exFAT_ReadFolder.ERROR_DEVICE \n" push ERROR_DEVICE jmp @f ;------------------------------------------------------------------------------ .done: ; DEBUGF 1, "K : exFAT_ReadFolder.done \n" ; DEBUGF 1, "K : exFAT_ReadFolder TotalBloks: %x\n", [edx+8] ; DEBUGF 1, "K : exFAT_ReadFolder Read Bloks: %x\n", [edx+4] add esp, 262*2+12 pushd 0 ; DEBUGF 1, "K : exFAT_ReadFolder.done ECX: %x\n", ecx dec ecx js @f ; DEBUGF 1, "K : exFAT_ReadFolder.ERROR_END_OF_FILE \n" mov byte [esp], ERROR_END_OF_FILE @@: mov ebx, [edx+4] ;------------------------------------------------------------------------------ .ret: ; DEBUGF 1, "K : exFAT_ReadFolder.ret \n" ; DEBUGF 1, "K : exFAT_ReadFile Return ESI:%x\n", esi call exFAT_unlock pop eax ; DEBUGF 1, "K : exFAT_ReadFile Return EBX:%x\n", ebx ; mov esi, [ebp+exFAT.LFN_reserve_place] ; push eax ; pushfd ; pop eax ; DEBUGF 1, "K : eFlags:%x\n",eax ; pop eax ; DEBUGF 1, "K : EAX:%x EBX:%x ECX:%x EDX:%x\n", eax, ebx, ecx, edx ; DEBUGF 1, "K : EBP:%x ESI:%x EDI:%x\n", ebp, esi, edi ret ;------------------------------------------------------------------------------ .error: ; DEBUGF 1, "K : exFAT_ReadFolder.error \n" push eax xor ebx, ebx jmp .ret ;------------------------------------------------------------------------------ .accessDenied: ; DEBUGF 1, "K : exFAT_ReadFolder.ERROR_ACCESS_DENIED \n" push ERROR_ACCESS_DENIED xor ebx, ebx jmp .ret ;------------------------------------------------------------------------------ exFAT_GetFileInfo: ; DEBUGF 1, "K : exFAT_GetFileInfo \n" ; DEBUGF 1, "K : exFAT F70 +00: %x\n", [ebx] ; DEBUGF 1, "K : exFAT F70 +04: %x\n", [ebx+4] ; DEBUGF 1, "K : exFAT F70 +08: %x\n", [ebx+8] ; DEBUGF 1, "K : exFAT F70 +12: %x\n", [ebx+12] ; DEBUGF 1, "K : exFAT F70 +16: %x\n", [ebx+16] ; DEBUGF 1, "K : exFAT F70 +20: %x\n", [ebx+20] ; DEBUGF 1, "K : exFAT Path: %s\n", esi cmp byte [esi], 0 jz .volume call exFAT_lock xor eax, eax mov [ebp+exFAT.need_hash], eax ; dword 0 mov [ebp+exFAT.hash_flag], eax ; dword 0 call exFAT_hd_find_lfn jc @f lea edi, [ebp+exFAT.file_dir_entry] push ebp xor ebp, ebp mov esi, [ebx+16] mov dword [esi+4], ebp call exFAT_entry_to_bdfe2 pop ebp xor eax, eax @@: push eax call exFAT_unlock pop eax @@: ret .volume: ; DEBUGF 1, "K : exFAT_GetFileInfo.volume \n" mov eax, dword[ebp+exFAT.Length] mov edx, dword[ebp+exFAT.Length+4] mov edi, [ebx+16] shld edx, eax, 9 shl eax, 9 mov [edi+36], edx mov [edi+32], eax mov eax, [ebx+8] mov byte [edi], 8 mov [edi+4], eax test eax, eax jz @b lea esi, [ebp+exFAT.volumeLabel] mov ecx, 11 @@: mov byte [esi+ecx], 0 dec ecx jz @f cmp byte [esi+ecx], ' ' jz @b @@: mov cl, 12 add edi, 40 cmp eax, 2 jz @f rep movsb xor eax, eax ret @@: lodsb stosw loop @b ret ;------------------------------------------------------------------------------ exFAT_SetFileInfo: ; DEBUGF 1, "K : exFAT_SetFileInfo \n" ; DEBUGF 1, "K : exFAT F70 +00: %x\n", [ebx] ; DEBUGF 1, "K : exFAT F70 +04: %x\n", [ebx+4] ; DEBUGF 1, "K : exFAT F70 +08: %x\n", [ebx+8] ; DEBUGF 1, "K : exFAT F70 +12: %x\n", [ebx+12] ; DEBUGF 1, "K : exFAT F70 +16: %x\n", [ebx+16] ; DEBUGF 1, "K : exFAT F70 +20: %x\n", [ebx+20] ; DEBUGF 1, "K : exFAT Path: %s\n", esi call exFAT_lock xor eax, eax mov [ebp+exFAT.need_hash], eax ; dword 0 mov [ebp+exFAT.hash_flag], eax ; dword 0 call exFAT_hd_find_lfn jc @f mov edi, [ebp+exFAT.buff_file_dir_pos] cmp eax, [ebp+exFAT.buff_file_dirsect] je .continue mov eax, [ebp+exFAT.buff_file_dirsect] mov [ebp+exFAT.buffer_curr_sector], eax push eax ebx lea ebx, [ebp+exFAT.buffer] call fs_read32_sys test eax, eax jz .continue_1 ; CF=0 pop ebx add esp, 4 jmp @f .continue_1: pop ebx eax .continue: push eax mov edx, [ebx+16] ; pointer to buffer with attributes (32 bytes) call exFAT_bdfe_to_fat_entry pop eax ; copy new File/Folder Directory Entry [0x85] for calculate SetChecksum field push esi edi xchg esi, edi lea edi, [ebp+exFAT.file_dir_entry] movsd movsd movsd movsd movsd movsd movsd movsd pop edi esi push eax call calculate_SetChecksum_field mov [edi+2], ax pop eax lea ebx, [ebp+exFAT.buffer] call fs_write32_sys call exFAT_update_disk xor eax, eax @@: push eax call exFAT_unlock pop eax ret ;------------------------------------------------------------------------------ exFAT_Delete: ; DEBUGF 1, "K : exFAT_Delete\n" ; DEBUGF 1, "K : exFAT F70 +00: %x\n", [ebx] ; DEBUGF 1, "K : exFAT F70 +04: %x\n", [ebx+4] ; DEBUGF 1, "K : exFAT F70 +08: %x\n", [ebx+8] ; DEBUGF 1, "K : exFAT F70 +12: %x\n", [ebx+12] ; DEBUGF 1, "K : exFAT F70 +16: %x\n", [ebx+16] ; DEBUGF 1, "K : exFAT F70 +20: %x\n", [ebx+20] ; DEBUGF 1, "K : exFAT Path: %s\n", esi call exFAT_lock xor eax, eax mov [ebp+exFAT.need_hash], eax ; dword 0 mov [ebp+exFAT.hash_flag], eax ; dword 0 ; and [ebp+exFAT.longname_sec1], 0 ; and [ebp+exFAT.longname_sec2], 0 mov [ebp+exFAT.longname_sec1], eax mov [ebp+exFAT.longname_sec2], eax call exFAT_hd_find_lfn jc .notFound ; cmp dword [edi], '. ' ; jz .access_denied2 ; cmp dword [edi], '.. ' ; jz .access_denied2 ; test byte [edi+11], 10h push eax lea eax, [ebp+exFAT.file_dir_entry] ; DEBUGF 1, "K : exFAT_Delete: File Attributes:%x\n", [eax+4] test byte [eax+4], 10000b pop eax jz .dodel ; we can delete only empty folders! pushad ; mov esi, [edi+20-2] ; mov si, [edi+26] ; esi=cluster lea eax, [ebp+exFAT.str_ext_dir_entry] mov esi, [eax+20] ; cluster ; DEBUGF 1, "K : exFAT_Delete: Cluster1:%x [EDI+20]:%x\n", esi, [edi+20] xor ecx, ecx lea eax, [esi-2] imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] add eax, [ebp+exFAT.DATA_START] ; add eax, [ebp+exFAT.CLUSTER_HEAP_START] lea ebx, [ebp+exFAT.buffer] call fs_read32_sys test eax, eax jnz .err1 lea eax, [ebx+0x200] ; add ebx, 2*0x20 .checkempty: ; DEBUGF 1, "K : exFAT_Delete.checkempty: [EBX]:%x\n", [ebx] cmp byte [ebx], 0 ; DIR_Name[0] == 0x00, then the directory entry is free jz .empty ; cmp byte [ebx], 0xE5 ; DIR_Name[0] == 0xE5, then the directory entry is free ; jnz .notempty cmp byte [ebx], 0x85 ; File/Folder Directory Entry of ExFAT jz .notempty cmp byte [ebx], 0xC0 ; Stream Extension Directory Entry of ExFAT jz .notempty cmp byte [ebx], 0xC1 ; File Name Extension Directory Entry of ExFAT jz .notempty add ebx, 0x20 cmp ebx, eax jb .checkempty inc ecx cmp ecx, [ebp+exFAT.SECTORS_PER_CLUSTER] jb @f mov eax, esi ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT inc eax ; inc cluster jmp .continue .get_FAT: ; DEBUGF 1, "K : exFAT_Delete.get_FAT:\n" call exFAT_get_FAT jc .err1 cmp eax, 2 jb .error_fat .continue: ; DEBUGF 1, "K : exFAT_Delete.continue:\n" cmp eax, [ebp+exFAT.fatRESERVED] jae .empty mov esi, eax xor ecx, ecx @@: ; DEBUGF 1, "K : exFAT_Delete.@@:\n" lea eax, [esi-2] imul eax, [ebp+exFAT.SECTORS_PER_CLUSTER] add eax, [ebp+exFAT.DATA_START] ; add eax, [ebp+exFAT.CLUSTER_HEAP_START] add eax, ecx lea ebx, [ebp+exFAT.buffer] call fs_read32_sys test eax, eax lea eax, [ebx+0x200] jz .checkempty .err1: ; DEBUGF 1, "K : exFAT_Delete.err1:\n" popad .err2: ; DEBUGF 1, "K : exFAT_Delete.err2:\n" push ERROR_DEVICE .ret: ; DEBUGF 1, "K : exFAT_Delete.ret:\n" call exFAT_unlock pop eax ret .notFound: ; DEBUGF 1, "K : exFAT_Delete.notFound:\n" push ERROR_FILE_NOT_FOUND jmp .ret .error_fat: ; DEBUGF 1, "K : exFAT_Delete.error_fat:\n" popad push ERROR_FS_FAIL jmp .ret .notempty: ; DEBUGF 1, "K : exFAT_Delete.notempty:\n" popad .access_denied2: ; DEBUGF 1, "K : exFAT_Delete.access_denied2:\n" push ERROR_ACCESS_DENIED jmp .ret .empty: ; DEBUGF 1, "K : exFAT_Delete.empty:\n" popad push eax ebx lea ebx, [ebp+exFAT.buffer] call fs_read32_sys test eax, eax pop ebx eax jnz .err2 .dodel: ; DEBUGF 1, "K : exFAT_Delete.dodel:\n" push eax ; mov eax, [edi+20-2] ; mov ax, [edi+26] ; eax=cluster lea eax, [ebp+exFAT.str_ext_dir_entry] mov eax, [eax+20] ; cluster ; DEBUGF 1, "K : exFAT_Delete: Cluster2:%x [EDI+20]:%x\n", eax, [edi+20] xchg eax, [esp] mov edi, [ebp+exFAT.buff_file_dir_pos] cmp eax, [ebp+exFAT.buff_file_dirsect] je .continue_2 mov eax, [ebp+exFAT.buff_file_dirsect] mov [ebp+exFAT.buffer_curr_sector], eax push eax ebx lea ebx, [ebp+exFAT.buffer] call fs_read32_sys test eax, eax jz .continue_1 ; CF=0 pop ebx add esp, 4 jmp .err2 .continue_1: ; DEBUGF 1, "K : exFAT_Delete.continue_1:\n" pop ebx eax .continue_2: ; DEBUGF 1, "K : exFAT_Delete.continue_2: EAX:%x\n", eax push ecx ; delete folder entry ; mov byte [edi], 0xE5 ; for FAT and byte [edi], 0x7F ; Entry Type is 0x85 is changed to 0x05 movzx ecx, byte [edi+1] ; Number of Secondary directory entries inc ecx ; delete LFN (if present) .lfndel: ; DEBUGF 1, "K : exFAT_Delete.lfndel: [EDI]:%x\n", [edi] add edi, 0x20 ; lea edx, [ebp+exFAT.buffer] lea edx, [ebp+exFAT.buffer+0x200] ; cmp edi, edx cmp edx, edi ja @f ; cmp [ebp+exFAT.longname_sec2], 0 ; jz .lfndone ; push [ebp+exFAT.longname_sec2] ; push [ebp+exFAT.longname_sec1] ; pop [ebp+exFAT.longname_sec2] ; and [ebp+exFAT.longname_sec1], 0 ; DEBUGF 1, "K : exFAT_Delete: lngnm_sec1:%x lngnm_sec2:%x\n", [ebp+exFAT.longname_sector1], [ebp+exFAT.longname_sector2] cmp [ebp+exFAT.longname_sector1], 0 je .longname_sec2 push eax mov eax, [ebp+exFAT.buff_file_dirsect] cmp eax, [ebp+exFAT.longname_sector1] pop eax ; je .longname_sec2 jne .longname_sec1 and [ebp+exFAT.longname_sector1], 0 jmp .longname_sec2 .longname_sec1: push [ebp+exFAT.longname_sector1] and [ebp+exFAT.longname_sector1], 0 jmp .longname_sec3 .longname_sec2: ; DEBUGF 1, "K : exFAT_Delete.longname_sec2:\n" cmp [ebp+exFAT.longname_sector2], 0 je .lfndone push eax mov eax, [ebp+exFAT.buff_file_dirsect] cmp eax, [ebp+exFAT.longname_sector2] pop eax je .lfndone push [ebp+exFAT.longname_sector2] and [ebp+exFAT.longname_sector2], 0 .longname_sec3: ; DEBUGF 1, "K : exFAT_Delete.longname_sec3:\n" push ebx ; mov ebx, edx lea ebx, [ebp+exFAT.buffer] call fs_write32_sys mov eax, [esp+4] ; DEBUGF 1, "K : exFAT_Delete: EAX:%x\n", eax call fs_read32_sys pop ebx pop eax ; lea edi, [ebp+exFAT.buffer+0x200] lea edi, [ebp+exFAT.buffer] @@: ; DEBUGF 1, "K : exFAT_Delete.@@: [EDI]:%x\n", [edi] ; sub edi, 0x20 ;; add edi, 0x20 ; cmp byte [edi], 0xE5 ; jz .lfndone dec ecx jz .lfndone cmp byte [edi], 0 jz .lfndone cmp byte [edi], 0x85 jz .lfndone ; cmp byte [edi+11], 0xF ; jnz .lfndone ; mov byte [edi], 0xE5 and byte [edi], 0x7F ; 0xC0 is changed to 0x40; 0xC1 is changed to 0x41 jmp .lfndel .lfndone: ; DEBUGF 1, "K : exFAT_Delete.lfndone:\n" pop ecx push ebx lea ebx, [ebp+exFAT.buffer] call fs_write32_sys pop ebx ; delete FAT chain pop eax call exFAT_clear_Cluster_Heap call exFAT_clear_cluster_chain call exFAT_update_disk call exFAT_unlock xor eax, eax ret ;------------------------------------------------------------------------------ calculate_SetChecksum_field: push ebx ecx edx esi edi lea esi, [ebp+exFAT.file_dir_entry] mov ecx, [ebp+exFAT.fname_extdir_offset] sub ecx, esi mov edx, esi mov edi, esi add edx, 2 ; (Index == 2) add edi, 3 ; (Index == 3) ; exFAT_calculate_SetChecksum_field ; in: ; esi -> file_dir_entry ; ecx -> NumberOfBytes ; out: ax = Checksum xor eax, eax xor ebx, ebx ;-------------------------------------- align 4 .start: ; DEBUGF 1, "Checksum start EAX:%x ECX:%x\n", eax, ecx cmp esi, edx ; (Index == 2) je .continue cmp esi, edi ; (Index == 3) je .continue mov bx, ax ; ((Checksum&1) ? 0x8000 : 0) and ax, 0x1 jz .else mov ax, 0x8000 jmp @f ;-------------------------------------- .else: xor ax, ax ;-------------------------------------- @@: ; DEBUGF 1, "(Checksum&1) EAX:%x\n", eax ; (Hash>>1) shr bx, 1 ; DEBUGF 1, "(Checksum>>1) EBX:%x\n", ebx add ax, bx ; DEBUGF 1, "+ (Checksum>>1) EAX:%x\n", eax movzx bx, byte [esi] add ax, bx ; DEBUGF 1, "+ (UInt16)Entries[Index] EAX:%x\n", eax .continue: inc esi dec ecx jnz .start ;-------------------------------------- lea ebx, [ebp+exFAT.file_dir_entry+2] mov [ebx], ax pop edi esi edx ecx ebx ret ;------------------------------------------------------------------------------ exFAT_clear_Cluster_Heap: ; in: eax = first cluster ;ClstHeap_change db ? ; 1=Cluster Heap has changed ;ClstHeap_in_cache dd ? ;ClstHeap_cache_ptr dd ? push eax ebx ecx edx esi mov ebx, [ebp+exFAT.ClstHeap_cache_ptr] push eax lea eax, [ebp+exFAT.str_ext_dir_entry] mov edx, [eax+12] ; high dword of real file size ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap Hdword file size:%x\n", edx mov eax, [eax+8] ; low dword of real file size ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap Ldword file size:%x\n", eax mov ecx, [ebp+exFAT.SECTORS_PER_CLUSTER] ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap SECTORS_PER_CLUSTER:%x\n", ecx shl ecx, 9 div ecx test edx, edx jz @f inc eax @@: mov edx, eax ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap number of clusters:%x\n", edx pop eax .start: ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap current cluster:%x\n", eax cmp eax, [ebp+exFAT.LAST_CLUSTER] ja .exit cmp eax, 2 jb .exit cmp eax, [ebp+exFAT.ROOT_CLUSTER] jz .exit push eax dec eax dec eax mov ecx, 7 and ecx, eax ; get offset of bits ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap offset of bits:%x\n", ecx shr eax, 3 mov esi, 511 and esi, eax ; get offset of bytes ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap offset of bytes:%x\n", esi shr eax, 9 ; get get offset of sectors ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap offset of sectors:%x\n", eax add eax, [ebp+exFAT.CLUSTER_HEAP_START] ; DEBUGF 1, "K : exFAT_clear_Cluster_Heap general offset:%x\n", eax cmp eax, [ebp+exFAT.ClstHeap_in_cache] je .inCache cmp [ebp+exFAT.ClstHeap_change], 0 je @f mov [ebp+exFAT.ClstHeap_change], 0 push eax mov eax, [ebp+exFAT.ClstHeap_in_cache] call fs_write32_sys pop eax @@: mov [ebp+exFAT.ClstHeap_in_cache], eax call fs_read32_sys test eax, eax jne .error .inCache: xor eax, eax mov al, [ebx+esi] ; get Cluster_Heap old value ; DEBUGF 1, "K : exFAT Cluster_Heap old value:%x\n", eax ror al, cl and al, 0xfe ; reset bit rol al, cl mov [ebx+esi], al ; save Cluster_Heap new value ; DEBUGF 1, "K : exFAT Cluster_Heap new value:%x\n", eax mov [ebp+exFAT.ClstHeap_change], 1 pop eax ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved ; DEBUGF 1, "K : exFAT General_Sec_Flags %x\n", [ebp+exFAT.General_Sec_Flags] test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT dec edx ; dec cluster counter jz .exit inc eax ; inc cluster jmp .start .get_FAT: call exFAT_get_FAT jc .ret jmp .start .error: pop eax stc jmp .ret .exit: clc .ret: pop esi edx ecx ebx eax ret ;------------------------------------------------------------------------------ exFAT_clear_cluster_chain: ; in: eax = first cluster ; DEBUGF 1, "K : exFAT_clear_cluster_chain: GSF:%x\n", [ebp+exFAT.General_Sec_Flags] ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved test byte [ebp+exFAT.General_Sec_Flags], 10b jz .set_FAT ret .set_FAT: push eax edx @@: cmp eax, [ebp+exFAT.LAST_CLUSTER] ja @f cmp eax, 2 jb @f cmp eax, [ebp+exFAT.ROOT_CLUSTER] jz @f xor edx, edx call exFAT_set_FAT jc .ret mov eax, edx jmp @b @@: clc .ret: pop edx eax ret ;------------------------------------------------------------------------------ exFAT_update_disk: cmp [ebp+exFAT.ClstHeap_change], 0 je @f mov [ebp+exFAT.ClstHeap_change], 0 push eax ebx mov eax, [ebp+exFAT.ClstHeap_in_cache] mov ebx, [ebp+exFAT.ClstHeap_cache_ptr] call fs_write32_sys pop ebx eax @@: cmp [ebp+exFAT.fat_change], 0 jz .noChange call exFAT_write_fat_sector .noChange: mov esi, [ebp+PARTITION.Disk] call disk_sync ret ;------------------------------------------------------------------------------ exFAT_write_fat_sector: push eax ebx ecx mov [ebp+exFAT.fat_change], 0 mov eax, [ebp+exFAT.fat_in_cache] cmp eax, -1 jz @f mov ebx, [ebp+exFAT.fat_cache_ptr] mov ecx, [ebp+exFAT.NUMBER_OF_FATS] .write_next_fat: push eax call fs_write32_sys pop eax add eax, [ebp+exFAT.SECTORS_PER_FAT] dec ecx jnz .write_next_fat @@: pop ecx ebx eax ret ;------------------------------------------------------------------------------ exFAT_notroot_next: ; DEBUGF 1, "K : exFAT_notroot_next\n" push ecx lea ecx, [ebp+exFAT.buffer+0x200-0x20] cmp edi, ecx jae exFAT_notroot_next_sector add edi, 0x20 @@: ; DEBUGF 1, "K : exFAT_notroot_next.ret\n" pop ecx ret ;exFAT_notroot_next_write: ; push ecx ; lea ecx, [ebp+exFAT.buffer+0x200] ; cmp edi, ecx ; jc @b ; push eax ; call exFAT_notroot_end_write ; pop eax exFAT_notroot_next_sector: ; DEBUGF 1, "K : exFAT_notroot_next_sector\n" push [ebp+exFAT.longname_sec2] pop [ebp+exFAT.longname_sec1] push eax ; DEBUGF 1, "K : exFAT_notroot_next.exFAT_get_sector In EAX:%x\n", eax call exFAT_get_sector ; DEBUGF 1, "K : exFAT_notroot_next.exFAT_get_sector Out EAX:%x\n", eax mov [ebp+exFAT.longname_sec2], eax pop eax mov ecx, [eax+4] inc ecx cmp ecx, [ebp+exFAT.SECTORS_PER_CLUSTER] jae exFAT_notroot_next_cluster mov [eax+4], ecx jmp @f exFAT_notroot_next_err: ; DEBUGF 1, "K : exFAT_notroot_next_err\n" ; dec ecx pop ecx ; js .1 movi eax, ERROR_FILE_NOT_FOUND ;.1: stc ret exFAT_notroot_next_cluster: ; DEBUGF 1, "K : exFAT_notroot_next_cluster\n" push eax mov eax, [eax] ; push edi ; lea edi, [ebp+exFAT.str_ext_dir_entry] ; Check - General Secondary Flags ; Bit 0 : Allocation possible ; 0 – No cluster allocated; 1 – cluster allocation is possible ; Bit 1 : No FAT chain ; 0 – Yes ; The clusters of this file/directory are NOT contiguous ; 1 – No; The Contiguous Cluster are allocated to this file/directory; ; This improves the File read performance ; Bits 2 – 7 : Reserved ; push eax ; movzx eax, byte [edi+1] ; DEBUGF 1, "K : exFAT_notroot_next_cluster GSF 1:%x\n", eax ; movzx eax, byte [ebp+exFAT.General_Sec_Flags] ; DEBUGF 1, "K : exFAT_notroot_next_cluster GSF 2:%x\n", eax ; pop eax ; test byte [edi+1], 10b ;11b ; pop edi test byte [ebp+exFAT.General_Sec_Flags], 10b jz .get_FAT inc eax jmp .continue .get_FAT: call exFAT_get_FAT .continue: mov ecx, eax pop eax jc exFAT_notroot_first.deverr cmp ecx, 2 jb exFAT_notroot_next_err cmp ecx, [ebp+exFAT.fatRESERVED] jae exFAT_notroot_next_err mov [eax], ecx and dword [eax+4], 0 @@: pop ecx exFAT_notroot_first: ; DEBUGF 1, "K : exFAT_notroot_first\n" ; DEBUGF 1, "K : exFAT_notroot_first.exFAT_get_sector In EAX:%x\n", eax call exFAT_get_sector ; DEBUGF 1, "K : exFAT_notroot_first.exFAT_get_sector Out EAX:%x\n", eax push ebx lea edi, [ebp+exFAT.buffer] mov ebx, edi sub [ebp+exFAT.valid_data_length], 512 mov [ebp+exFAT.buffer_curr_sector], eax call fs_read32_sys pop ebx test eax, eax jz .ret ; CF=0 push ecx .deverr: ; DEBUGF 1, "K : exFAT_notroot_first.deverr\n" pop ecx mov eax, ERROR_DEVICE stc .ret: ; DEBUGF 1, "K : exFAT_notroot_first.ret\n" 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 ;-------------------------------------- exFAT_get_sector: ; DEBUGF 1, "K : exFAT_get_sector\n" push ecx mov ecx, [eax] ; DEBUGF 1, "K : exFAT_get_sector In [EAX]:%x [EAX+4]:%x\n", ecx, [eax+4] dec ecx dec ecx imul ecx, [ebp+exFAT.SECTORS_PER_CLUSTER] ; add ecx, [ebp+exFAT.DATA_START] add ecx, [ebp+exFAT.CLUSTER_HEAP_START] add ecx, [eax+4] mov eax, ecx pop ecx ret ;------------------------------------------------------------------------------