Paste Description for FAT Source Code
FAT filesystem driver Source Code
by Toaster a lá Peter Kleissner
- FAT Source Code
- Monday, April 2nd, 2007 at 10:49:08am MDT
- Copyright (C) 2005-2007 Peter Kleissner
- see www.toasteros.at.tt -> Impressum -> License // http://t0ast3r.t0.ohost.de/index.php?page=impressum&sub=license
- just see, learn, don't copy
- ---==== Published under the ToasterOS GENERAL PUBLIC LICENSE ===---
- ; FAT functions
- ; - Get_Short_Name
- ; - Determine_FAT_Type
- ; - Get_Count_of_Clusters
- ; - Get_DataSec
- ; - First_Sector_of_Cluster
- ; - Get_First_Data_Sector
- ; - Get_Root_Dir_Sectors
- ; - Get_FirstRootDirSecNum
- ; - Get_FATSz
- ; - Get_TotSec
- ; - Get_FATSecNum_Offset
- ; - Read_FAT_entry
- ; - Write_FAT_entry
- ; - Get_Next_Cluster
- ; - Get_Entry_Count
- ; - Return_SecPerClusVal
- Determine_FAT_Type:
- ; [Drive] = drive to determine the FAT type
- ; return:
- ; all FAT values in Drive_Buffer are set correct (inclusive FAT determination)
- ; read the BIOS Parameter Block
- Read 0, 1, Open_File_Destroy
- ; copy relevant values of the BIOS Parameter Block
- ; set "Sectors per Cluster"
- movzx ebx,byte [API_Buffer+13]
- mov [Drive_Buffer+0Bh],bl
- ; set "dwords per Sector"
- movzx eax,word [API_Buffer+11]
- shr ax,2
- mov [Drive_Buffer+0Ch],ax
- ; set "dwords per Cluster"
- mul ebx ; Sectors per Cluster" * "dwords per Sector"
- mov [Drive_Buffer+0Eh],eax
- ; set "File Allocation Table" (= "Reserved Sector Count")
- mov ax,word [API_Buffer+14] ; FAT Offset = Reserved Sector Count
- mov [Drive_Buffer+1Ch],ax
- ; set the value "First_Data_Sector"
- call Get_First_Data_Sector
- ; ---- OBSOLETE ----
- ; set the value "entries per cluster"
- ;call Get_Entry_Count
- ; ---- OBSOLETE ----
- ; set the value "FAT Type"
- call Get_Count_of_Clusters
- ; set the values "first root directory sector" and "last root directory sector"
- call Get_FirstRootDirSecNum
- ret
- Get_First_Data_Sector:
- ; static function (only called once), needs BIOS Parameter Block
- ; writes "First_Data_Sector" into Drive_Buffer
- ; (BPB_NumFATs * FATSz)
- call Get_FATSz
- movzx ebx,byte [API_Buffer+16]
- mul ebx
- ; BPB_ResvdSecCnt + (BPB_NumFATs * FATSz)
- movzx ecx,word [API_Buffer+14]
- add ecx,eax
- ; BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors
- call Get_Root_Dir_Sectors
- add eax,ecx
- mov [Drive_Buffer+12h],eax ; set "first data sector"
- ret
- Get_FATSz:
- ; static function (only called once), needs BIOS Parameter Block
- ; returns the FATSz
- ; C++
- ; If(BPB_FATSz16 != 0)
- ; FATSz = BPB_FATSz16;
- ; Else
- ; FATSz = BPB_FATSz32;
- ; Assembler
- movzx eax,word [API_Buffer+22] ; eax = BPB_FATSz16
- or eax,eax ; eax = 0 ?
- jnz Get_FATSz_Exit ; if not zero, it's FATSz16
- ; else it's FATSz32
- mov eax,[API_Buffer+36] ; eax = BPB_FATSz32
- Get_FATSz_Exit:
- ret
- Get_Count_of_Clusters:
- ; static function (only called once), needs BIOS Parameter Block
- ; writes "FAT Type" into Drive_Buffer
- ; CountofClusters = DataSec / BPB_SecPerClus
- call Get_DataSec
- xor edx,edx
- movzx ebx,byte [Drive_Buffer+0Bh]
- div ebx
- ; C++
- ; If(CountofClusters < 4085)
- ; /* Volume is FAT12 */
- ; else
- ; if(CountofClusters < 65525)
- ; /* Volume is FAT16 */
- ; else
- ; /* Volume is FAT32 */
- ; Assembler
- mov [Drive_Buffer+0Ah],byte 12 ; suppose FAT Type is FAT12
- cmp eax,4085
- jl Determine_FAT_Type_Exit ; if CountofClusters < 4085 exit
- mov [Drive_Buffer+0Ah],byte 16 ; suppose FAT Type is FAT16
- cmp eax,65525
- jl Determine_FAT_Type_Exit ; if CountofClusters < 65525 exit
- ; else FAT Type is FAT32
- mov [Drive_Buffer+0Ah],byte 32
- Determine_FAT_Type_Exit:
- ret
- Get_DataSec:
- ; static function (only called once), needs BIOS Parameter Block and returns static value
- ; return = DataSec
- ; DataSec = TotSec - FirstDataSector
- call Get_TotSec
- sub eax,[Drive_Buffer+12h]
- ret
- Get_TotSec:
- ; static function (only called once), needs BIOS Parameter Block and returns static value
- ; return = TotSec
- ; C++
- ; If(BPB_TotSec16 != 0)
- ; TotSec = BPB_TotSec16;
- ; Else
- ; TotSec = BPB_TotSec32;
- ; Assembler
- movzx eax,word [API_Buffer+19] ; eax = BPB_TotSec16
- or eax,eax ; eax = 0 ?
- jnz Get_TotSec_Exit ; if not zero, it's TotSec16
- ; else it's TotSec32
- mov eax,[API_Buffer+32] ; eax = BPB_TotSec32
- Get_TotSec_Exit:
- ret
- Get_Root_Dir_Sectors:
- ; static function (only called once), needs BIOS Parameter Block
- ; return = Root Directory Sectors
- ; (BPB_RootEntCnt * 32)
- movzx eax,word [API_Buffer+17]
- imul eax,32
- ; eax = zero ? (only on FAT32 drives)
- or eax,eax
- jz Get_Root_Dir_Sectors_Exit
- ; (BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)
- movzx edx,word [API_Buffer+11]
- dec edx
- add eax,edx
- ; ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec
- xor edx,edx
- movzx ebx,word [API_Buffer+11]
- div ebx
- Get_Root_Dir_Sectors_Exit:
- ret
- Get_FirstRootDirSecNum:
- ; static function (only called once), needs BIOS Parameter Block
- ; writes "first root directory sector" and "last root directory sector" into Drive_Buffer
- ; share function into FAT12/16 and FAT32
- cmp [Drive_Buffer+0Ah],byte 32
- je Get_FirstRootDirSecNum_FAT32
- ; FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz);
- call Get_FATSz
- movzx ebx,byte [API_Buffer+16]
- mul ebx ; BPB_FATSz * BPB_NumFATs
- movzx ebx,word [API_Buffer+14]
- add eax,ebx ; BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16)
- mov [Drive_Buffer+16h],eax ; set "first root directory sector"
- call Get_Root_Dir_Sectors ; calculate last root directory sector (add values)
- add ax,[Drive_Buffer+16h]
- mov [Drive_Buffer+1Ah],ax ; set "last root directory sector"
- ret
- Get_FirstRootDirSecNum_FAT32:
- ; FirstRootDirSecNum = BPB_RootClus * Sectors per Cluster
- mov eax,[API_Buffer+44]
- imul eax,[API_Buffer+13]
- mov [Drive_Buffer+16h],eax ; set "first root directory sector"
- mov [Drive_Buffer+1Ah],word 00h ; set "last root directory sector" (on FAT32 not avl)
- ret
- %if 0 = 1
- Get_Entry_Count:
- ; static function (only called once), needs BIOS Parameter Block
- ; writes "entries per cluster" into Drive_Buffer
- ; calculate the count of entrys per sector (BPB_BytsPerSec / Entry_Size)
- movzx eax,word [API_Buffer+11]
- xor edx,edx
- mov ebx,32
- div ebx
- ; calculate the count of entries per cluster
- movzx ebx,byte [API_Buffer+13]
- mul ebx ; * sectors per cluster
- mov [Drive_Buffer+1Ch],eax ; set "entries per cluster"
- ret
- %endif
- ; non static functions, which are called more than once and returns non static values
- First_Sector_of_Cluster:
- ; normal FAT32 ?
- cmp [Drive_Buffer+0Ah],byte 32
- je First_Sector_of_Cluster_normal
- ; normal cluster type ?
- cmp [cluster_type],byte 18h
- jne First_Sector_of_Cluster_normal
- ; else the cluster is a sector in the root directory area
- ; (do nothing)
- ret
- ; eax = cluster n
- ; return = first sector of cluster n
- ; n - 2
- First_Sector_of_Cluster_normal:
- dec eax
- dec eax
- ; (n - 2) * BPB_SecPerClus
- movzx ebx,byte [Drive_Buffer+0Bh]
- mul ebx
- ; ((n - 2) * BPB_SecPerClus) + FirstDataSector
- add eax,[Drive_Buffer+12h]
- ret
- Get_FATSecNum_Offset:
- ; eax = cluster number n
- ; return = sector to read (element of the File Allocation Table)
- ; reutrn(edx) = Offset in the EFFECTIVE sector
- ; if FAT12 is set, and offset streches over boundarys, the carry flag is set
- ; in all other cases (non FAT12 or in boundarys) the carry flag is cleared
- ; If(FATType == FAT16)
- ; FATOffset = N * 2;
- ; Else
- ; if (FATType == FAT32)
- ; FATOffset = N * 4;
- ;
- ; ThisFATSecNum = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);
- ; ThisFATEntOffset = REM(FATOffset / BPB_BytsPerSec);
- ; special FAT12?
- cmp [Drive_Buffer+0Ah],byte 12
- je Get_FATSecNum_Offset_FAT12
- ; calculate the FATOffset (N * 2 or 4)
- shl eax,1 ; suppose FAT Type is 16
- cmp [Drive_Buffer+0Ah],byte 16
- je Calculate_ThisFAT ; if FAT 16, exit
- shl eax,1 ; else mul one more with 2 (in effect eax * 4)
- Calculate_ThisFAT:
- ; FATOffset / BPB_BytsPerSec
- xor edx,edx
- sub ebx,ebx
- imul bx, word [Drive_Buffer+0Ch], 4 ; bx = bytes per sector
- div ebx ; return(edx) = Offset in sector
- ; BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec)
- movzx ebx,word [Drive_Buffer+1Ch]
- add eax,ebx ; return = sector
- clc
- ret
- Get_FATSecNum_Offset_FAT12:
- ; FATOffset = N + (N / 2);
- ; /* Multiply by 1.5 without using floating point, the divide by 2 rounds DOWN */
- ; ThisFATSecNum = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);
- ; ThisFATEntOffset = REM(FATOffset / BPB_BytsPerSec);
- ;
- ; We now have to check for the sector boundary case:
- ;
- ; If(ThisFATEntOffset == (BPB_BytsPerSec – 1)) {
- ; /* This cluster access spans a sector boundary in the FAT */
- ; /* There are a number of strategies to handling this. The */
- ; /* easiest is to always load FAT sectors into memory */
- ; /* in pairs if the volume is FAT12 (if you want to load */
- ; /* FAT sector N, you also load FAT sector N+1 immediately */
- ; /* following it in memory unless sector N is the last FAT */
- ; /* sector). It is assumed that this is the strategy used here */
- ; /* which makes this if test for a sector boundary span */
- ; /* unnecessary. */
- ; }
- ; the same code as by "Calculate_ThisFAT"
- ; FATOffset / BPB_BytsPerSec
- xor edx,edx
- sub ebx,ebx
- imul bx, word [Drive_Buffer+0Ch], 4 ; bx = bytes per sector
- div ebx ; return(edx) = Offset in sector
- ; BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec)
- movzx ebx,word [Drive_Buffer+1Ch]
- add eax,ebx ; return = sector
- ; If(ThisFATEntOffset == (BPB_BytsPerSec – 1)) then boundary strech
- dec ebx
- cmp edx,ebx
- je Get_FATSecNum_Offset_FAT12_boundary
- clc
- ret
- ; if here, the entry is over boundarys, so set cf to indicate it
- Get_FATSecNum_Offset_FAT12_boundary:
- stc
- ret
- Read_FAT_entry:
- ; eax = Cluster
- mov [Temp],eax ; store the Cluster temporary (for FAT12)
- ; special FAT12?
- cmp [Drive_Buffer+0Ah],byte 12
- je Read_FAT12_entry
- call Get_FATSecNum_Offset ; get the Sector and the Offset of the entry
- ; read the SST
- Read eax, 1, Read_FAT_Entry_Exit
- ; now share the function into FAT16 and FAT32
- cmp [Drive_Buffer+0Ah],byte 32
- je Read_FAT32_entry
- lea edi,[API_Buffer+edx] ; edi = Offset in the Buffer
- movzx eax,word [edi] ; eax = searched entry
- jmp Read_FAT_Entry_succ
- Read_FAT32_entry:
- lea edi,[API_Buffer+edx] ; edi = Offset in the Buffer
- mov eax,[edi] ; eax = searched entry
- ;jmp Read_FAT_Entry_succ
- Read_FAT_Entry_succ:
- clc
- Read_FAT_Entry_Exit:
- ret
- Read_FAT12_entry: ; now: same code as by Read_FAT16/32_entry
- call Get_FATSecNum_Offset ; get the Sector and the Offset of the entry
- jc Read_FAT12_entry_boundary ; if the entry streches about sector boundarys, handle special
- ; read the SST
- Read eax, 1, Read_FAT_Entry_Exit
- lea edi,[API_Buffer+edx*2] ; edi = Offset in the Buffer
- movzx eax,word [edi] ; eax = searched (word) entry
- ; odd?
- test [Temp],dword 01b
- je Read_FAT12_entry_odd
- ; if here, we want the low 12 bits of the word, so clear the other (and exit)
- or eax,0F000h
- xor eax,0F000h
- jmp Read_FAT_Entry_succ
- Read_FAT12_entry_odd:
- ; if here, we want only the high 12 bits of the word, so shift right about 4 bits (and exit)
- shr eax,4
- jmp Read_FAT_Entry_succ
- Read_FAT12_entry_boundary: ; if here, the entry streches over sector boundarys
- mov [Temp],eax ; save the sector
- ; read the SST
- Read eax, 1, Read_FAT_Entry_Exit
- lea edi,[API_Buffer+edx*2] ; edi = Offset in the Buffer
- ; restore the needed sector (+ 1 !)
- mov eax,[Temp]
- inc eax
- ; read the LEAST 4 bits of the ENTRY, which are - in fact - the HIGH NIBBLE bits of the read byte
- mov bl,[edi] ; just use bl instead of al; bl wouldn't change by the ToasterOS function definition
- ; read the next Sector of the SST
- Read eax, 1, Read_FAT_Entry_Exit
- ; now merge the 4 bits in bl and the byte at API_Buffer + 0
- movzx eax,byte [API_Buffer+0]
- shl eax,4 ; shl the byte (by 4 bits)
- shr bl,4 ; the high nibble of the byte is the low nibble we need
- or al,bl ; add the entry (end exit)
- clc
- ret
- Write_FAT_entry:
- ; eax = Cluster
- ; ebx = value; or implicit used bx/b12 for using FAT12, FAT16
- ; the caller shouldn't determine the size of using, because all FAT functions return 32 bit (probably zero extended) values
- ; maintaily the code (explicit the initialising process) is the same as by Read_FAT_Entry
- mov [Temp],eax ; store the Cluster temporary (for FAT12)
- ; special FAT12?
- cmp [Drive_Buffer+0Ah],byte 12
- je Write_FAT12_entry
- push ebx ; store ebx, it will be used in Get_FATSecNum_Offset
- call Get_FATSecNum_Offset ; get the Sector and the Offset of the entry
- pop ebx ; restore ebx
- add eax,[Drive_Buffer+1Ch] ; eax = sector to modify
- mov ecx,eax ; store to-change sector
- ; read the SST
- Read eax, 1, Write_FAT_Entry_Exit
- ; now share the function into FAT16 and FAT32
- cmp [Drive_Buffer+0Ah],byte 32
- je Write_FAT32_entry
- lea edi,[API_Buffer+edx*2] ; edi = Offset in the Buffer
- mov [edi],bx ; store new data into the entry
- jmp Write_entry
- Write_FAT32_entry:
- lea edi,[API_Buffer+edx*4] ; edi = Offset in the Buffer
- mov [edi],ebx ; store new data (now 32 bit) into the entry
- Write_entry: ; write the to-change sector
- Write_into ecx, 1
- Write_FAT_Entry_Exit:
- ret
- Write_FAT12_entry: ; now: same code as by Read/Write_FAT16/32_entry
- push ebx ; store ebx, it will be used in Get_FATSecNum_Offset
- call Get_FATSecNum_Offset ; get the Sector and the Offset of the entry
- pop ebx ; restore ebx
- jc Write_FAT12_entry_boundary ; if the entry streches about sector boundarys, handle special
- add eax,[Drive_Buffer+1Ch] ; eax = sector to modify
- mov ecx,eax
- ; read the SST
- Read eax, 1, Write_FAT_Entry_Exit
- lea edi,[API_Buffer+edx*2] ; edi = Offset in the Buffer
- mov ax,[edi] ; eax = searched (word) entry
- ; odd?
- test [Temp],dword 01b
- je Write_FAT12_entry_odd
- ; if here, we want to change the low 12 bits of the word, so clear the other
- or ebx,0F000h
- xor ebx,0F000h ; clear high 4 bits of the value to store (also: or)
- or ax,bx
- mov ax,[edi]
- jmp Write_entry
- Write_FAT12_entry_odd:
- ; if here, we want to change only the high 12 bits of the word, so shift right about 4 bits
- or ebx,0F000h
- xor ebx,0F000h ; clear high 4 bits of the value to store (also: or)
- shr ebx,4 ; shift ebx, the value
- or ax,bx
- mov ax,[edi]
- jmp Write_entry
- Write_FAT12_entry_boundary: ; if here, the entry streches over sector boundarys
- add eax,[Drive_Buffer+1Ch] ; eax = sector to modify
- mov ecx,eax
- ; read the SST
- Read eax, 1, Write_FAT_Entry_Exit
- lea edi,[API_Buffer+edx*2] ; edi = Offset in the Buffer
- ; modify the top 4 bits of the byte, which are the least 4 bits of the entry
- mov al,[edi]
- mov dl,bl
- or dl,00001111b
- xor dl,00001111b
- or al,bl
- mov [edi],al
- ; write the first to-change sector
- Write_into ecx, 1, Write_FAT_Entry_Exit
- ; restore the needed sector (+ 1 !)
- inc ecx
- ; read the next Sector of the SST
- Read ecx, 1, Write_FAT_Entry_data_losing
- ; store the remaining byte of the entry
- shr ebx,4
- mov [API_Buffer+0],bl
- ; write the second to-change sector
- Write_into ecx, 1, Write_FAT_Entry_data_losing
- jmp Write_FAT_Entry_Exit
- Write_FAT_Entry_data_losing:
- ; comes here if there is an error while accessing (reading or writting) a FAT12 entry streches over sector boundarys
- ; contact security guard/change to security mode?
- ; ?
- ret
- Get_Next_Cluster:
- ; eax = Cluster
- ; even on FAT12/16 root directorys it's interpreted as cluster size
- ; this function gets the next CLUSTER of any directory (specified by the given cluster), included the Root Directory
- ; cf is set if EOF is reached, then return = entry
- ; share into FAT12/16 and FAT32
- cmp [Drive_Buffer+0Ah],byte 32
- je Get_Next_Cluster_FAT32
- ; check if cluster is a sector of the FAT12/16 root directory
- cmp [cluster_type],byte 18h
- jne Get_Next_Cluster_no_root_directory
- ; if here, the cluster is a sector of the root directory
- ; if (Sectors per Cluster + Current Cluster) > Last_Root_Dir_Sector then EOC is reached
- push bx
- movzx bx,byte [Drive_Buffer+0Bh]
- add ax,bx ; add Sectors per Cluster
- pop bx
- cmp [Drive_Buffer+1Ah],ax ; eax > last sector of the root directory?
- jnl Get_Next_Cluster_RD_inc
- ; if here, the last sector of the root directory is reached, so there is no more cluster
- mov eax,0FFFFFFFFh ; EOC is reached
- stc
- ret
- Get_Next_Cluster_RD_inc: ; normal exit (already incremented)
- ; eax is already up to date (because of the add Sectors per Cluster)
- clc
- ret
- Get_Next_Cluster_no_root_directory: ; share into FAT12 and FAT16
- cmp [Drive_Buffer+0Ah],byte 16
- je Get_Next_Cluster_FAT16
- Get_Next_Cluster_FAT12:
- call Read_FAT_entry
- ; EOF reached?
- cmp eax,0FF8h
- jl Get_Next_Cluster_succ ; if (eax < 0FF8h) then it's not the end
- ; else set cf (and exit)
- stc
- ret
- Get_Next_Cluster_FAT16:
- call Read_FAT_entry
- ; EOF reached?
- cmp eax,0FFF8h
- jl Get_Next_Cluster_succ ; if (eax < 0FFF8h) then it's not the end
- ; else set cf (and exit)
- stc
- ret
- Get_Next_Cluster_FAT32:
- call Read_FAT_entry
- ; the function returns a (32 bit) pointer, but on FAT32 entries there are only 28 bits used, so clear the top 4 bits
- or eax,0F0000000h
- xor eax,0F0000000h
- ; EOF reached?
- cmp eax,0FFFFFF8h
- jl Get_Next_Cluster_succ ; if (eax < 0FFFFFF8h) then it's not the end
- ; else set cf (and exit)
- stc
- ret
- Get_Next_Cluster_succ:
- clc
- ret
advertising
Update the Post
Either update this post and resubmit it with changes, or make a new post.
You may also comment on this post.
Please note that information posted here will expire by default in one month. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.