kolibrios-fun/kernel/trunk/fs/ext.inc

2448 lines
65 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
; EXT external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> EXTFS structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
ext_user_functions:
dd ext_free
dd (ext_user_functions_end - ext_user_functions - 4) / 4
dd ext_ReadFile
dd ext_ReadFolder
dd ext_CreateFile
dd ext_WriteFile
dd ext_SetFileEnd
dd ext_GetFileInfo
dd ext_SetFileInfo
dd 0
dd ext_Delete
dd ext_CreateFolder
ext_user_functions_end:
endg
struct DIRENTRY
inodeNumber dd ?
entryLength dw ?
nameLength db ?
fileType db ?
name db ? ; rb [nameLength]
ends
struct INODE
accessMode dw ?
UID dw ?
fileSize dd ?
accessedTime dd ?
inodeModified dd ?
dataModified dd ?
deletedTime dd ?
GID dw ?
linksCount dw ?
sectorsUsed dd ?
featureFlags dd ?
reserved dd ?
blockNumbers rd 12
addressBlock dd ?
doubleAddress dd ?
tripleAddress dd ?
generation dd ?
ACL dd ?
fileSizeHigh dd ?
ends
struct BGDESCR ; block group descriptor
blockBitmap dd ?
inodeBitmap dd ?
inodeTable dd ?
blocksFree dw ?
inodesFree dw ?
directoriesCount dw ?
reserved rb 14
ends
struct SUPERBLOCK
inodesTotal dd ?
blocksTotal dd ?
blocksReserved dd ?
blocksFree dd ?
inodesFree dd ?
firstGroupBlock dd ?
sectorsPerBlockLog dd ? ; shift for 1024
fragmentSizeLog dd ?
blocksPerGroup dd ?
fragmentsPerGroup dd ?
inodesPerGroup dd ?
lastMountTime dd ?
lastWriteTime dd ?
mountCount dw ?
mountMax dw ?
magic dw ?
state dw ?
errorHandling dw ?
additionalVersion dw ?
lastCheck dd ?
checkInterval dd ?
creatorOS dd ?
dynamicVersionFlag dd ?
reservedUID dw ?
reservedGID dw ?
firstInode dd ?
inodeSize dw ?
thisBlockGroup dw ?
compatibleFlags dd ?
incompatibleFlags dd ?
RO_compatibleFlags dd ?
ends
; ext4 extent tree
struct NODEHEADER ; tree node header
magic dw ? ; 0xF30A
entriesFolow dw ?
entriesMax dw ?
currentDepth dw ?
generation dd ?
ends
struct INDEX ; root/branch
fileBlock dd ?
nodeBlock dd ?
nodeBlockHigh dw ?
reserved dw ?
ends
struct EXTENT ; leaf
fileBlock dd ?
blocksCount dw ?
fsBlockHigh dw ?
fsBlock dd ?
ends
ROOT_INODE = 2
PERMISSIONS = 110110110b
EXTENTS_USED = 80000h
TYPE_MASK = 0F000h
FLAG_FILE = 8000h
DIRECTORY = 4000h
DIR_FLAG_FILE = 1
DIR_DIRECTORY = 2
KOS_HIDDEN = 2
KOS_DIRECTORY = 10h
READ_ONLY = 1
; Implemented "incompatible" features:
; 2 = have file type in directory entry
; 40h = extents
; 200h = flexible block groups
INCOMPATIBLE_SUPPORT = 242h
; Read only support for "incompatible" features:
INCOMPATIBLE_READ_SUPPORT = 240h
; Implemented "read-only" features:
; 1 = sparse superblock
; 2 = 64-bit file size
READ_ONLY_SUPPORT = 3
struct EXTFS PARTITION
Lock MUTEX
mountType dd ?
sectorsPerBlockLog dd ? ; shift for 512
bytesPerBlock dd ?
sectorsPerBlock dd ?
dwordsPerBlock dd ?
dwordsPerBranch dd ? ; dwordsPerBlock ^ 2
mainBlockBuffer dd ?
tempBlockBuffer dd ?
align 512
superblock SUPERBLOCK
align 1024
rootInodeBuffer INODE
align 1024
mainInodeBuffer INODE
align 1024
tempInodeBuffer INODE
ends
; mount if it's a valid EXT partition
ext2_create_partition:
; in:
; ebp -> PARTITION structure
; ebx -> boot sector
; ebx+512 -> buffer
; out:
; eax -> EXTFS structure, 0 = not EXT
push ebx
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .fail
mov eax, 2
add ebx, 512
call fs_read32_sys
test eax, eax
jnz .fail
cmp [ebx+SUPERBLOCK.magic], 0xEF53
jne .fail
cmp [ebx+SUPERBLOCK.state], 1
ja .fail
test [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT
jnz .fail
cmp [ebx+SUPERBLOCK.sectorsPerBlockLog], 6 ; 64KB
ja .fail
cmp [ebx+SUPERBLOCK.inodeSize], 1024
ja .fail
cmp [ebx+SUPERBLOCK.blocksPerGroup], 0
je .fail
cmp [ebx+SUPERBLOCK.inodesPerGroup], 0
je .fail
stdcall kernel_alloc, 1000h
test eax, eax
jz .fail
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+EXTFS.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+EXTFS.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+EXTFS.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+EXTFS.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+EXTFS.Disk], ecx
mov [eax+EXTFS.FSUserFunctions], ext_user_functions
push ebp esi edi
mov ebp, eax
lea ecx, [eax+EXTFS.Lock]
call mutex_init
mov esi, ebx
lea edi, [ebp+EXTFS.superblock]
mov ecx, 512/4
rep movsd ; copy superblock
mov ecx, [ebx+SUPERBLOCK.sectorsPerBlockLog]
inc ecx
mov [ebp+EXTFS.sectorsPerBlockLog], ecx
mov eax, 1
shl eax, cl
mov [ebp+EXTFS.sectorsPerBlock], eax
shl eax, 9
mov [ebp+EXTFS.bytesPerBlock], eax
shl eax, 1
push eax
shr eax, 3
mov [ebp+EXTFS.dwordsPerBlock], eax
mul eax
mov [ebp+EXTFS.dwordsPerBranch], eax
call kernel_alloc
test eax, eax
jz .error
mov [ebp+EXTFS.mainBlockBuffer], eax
add eax, [ebp+EXTFS.bytesPerBlock]
mov [ebp+EXTFS.tempBlockBuffer], eax
mov [ebp+EXTFS.mountType], 0
test [ebx+SUPERBLOCK.RO_compatibleFlags], not READ_ONLY_SUPPORT
jnz .read_only
test [ebx+SUPERBLOCK.incompatibleFlags], INCOMPATIBLE_READ_SUPPORT
jz @f
.read_only:
or [ebp+EXTFS.mountType], READ_ONLY
@@: ; read root inode
lea ebx, [ebp+EXTFS.rootInodeBuffer]
mov eax, ROOT_INODE
call readInode
test eax, eax
jnz @f
mov eax, ebp
pop edi esi ebp ebx
ret
@@:
stdcall kernel_free, [ebp+EXTFS.mainBlockBuffer]
.error:
stdcall kernel_free, ebp
pop edi esi ebp
.fail:
pop ebx
xor eax, eax
ret
; unmount EXT partition
ext_free:
; in: eax -> EXTFS structure
push eax
stdcall kernel_free, [eax+EXTFS.mainBlockBuffer]
call kernel_free
ret
extfsWriteBlock:
push fs_write64_sys
jmp @f
; in:
; eax = block number
; ebx -> buffer
extfsReadBlock:
push fs_read64_sys
@@:
push ecx edx
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
call dword[esp+8]
pop edx ecx
add esp, 4
test eax, eax
jz @f
movi eax, ERROR_DEVICE
stc
@@:
ret
extfsReadDescriptor:
; in: eax = block group number
; out:
; [ebp+EXTFS.tempBlockBuffer] -> relevant block
; eax -> block group descriptor, 0 = error
push edx ebx
shl eax, 5
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
add eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail
mov eax, ebx
add eax, edx
@@:
pop ebx edx
ret
.fail:
xor eax, eax
stc
jmp @b
extfsWriteDescriptor:
; in:
; eax = block group number
; [ebp+EXTFS.tempBlockBuffer] -> relevant block
push edx ebx
shl eax, 5
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
add eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
pop ebx edx
ret
extfsResourceFree:
; in:
; ecx=0 -> block, ecx=1 -> inode
; eax = block/inode number
push ebx edx
sub eax, [ebp+EXTFS.superblock.firstGroupBlock]
xor edx, edx
div [ebp+EXTFS.superblock.blocksPerGroup]
push eax edx
call extfsReadDescriptor
jc .fail
inc [eax+BGDESCR.blocksFree+ecx*2]
mov eax, [eax+BGDESCR.blockBitmap+ecx*4]
mov ebx, [ebp+EXTFS.mainBlockBuffer]
mov edx, eax
call extfsReadBlock
jc .fail
pop eax
push edx
mov edx, eax
and edx, 31
shr eax, 5
shl eax, 2
add eax, [ebp+EXTFS.mainBlockBuffer]
btr [eax], edx
pop eax
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
jc @f
inc [ebp+EXTFS.superblock.blocksFree+ecx*4]
pop eax
call extfsWriteDescriptor
.ret:
pop edx ebx
ret
.fail:
pop eax
@@:
pop eax
movi eax, ERROR_DEVICE
jmp .ret
freeDoublyIndirectBlock:
; in: eax = doubly-indirect block number
; out: eax=1 -> finished
test eax, eax
jz .complete
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
pop eax
jc .ret
xor ecx, ecx
call extfsResourceFree
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
@@:
mov eax, [ebx]
test eax, eax
jz .complete
call extfsResourceFree
add ebx, 4
cmp ebx, edx
jb @b
.ret:
xor eax, eax
ret
.complete:
inc eax
ret
inodeBlockAlloc:
; in: esi -> inode
; out: ebx = block number
; TODO: fix to have correct preference.
mov eax, ROOT_INODE
call extfsBlockAlloc
jc @f
mov eax, [ebp+EXTFS.sectorsPerBlock]
add [esi+INODE.sectorsUsed], eax
xor eax, eax
@@:
ret
extfsBlockAlloc: ; also erases
; in: eax = inode number
; out: ebx = block number
xor ebx, ebx
call extfsResourceAlloc
jc @f
push ebx ecx edi
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov ebx, edi
xor eax, eax
rep stosd
pop edi ecx
mov eax, [esp]
call extfsWriteBlock
pop ebx
@@:
ret
extfsResourceAlloc:
; in:
; eax = inode number
; ebx=0 -> block, ebx=1 -> inode
; out:
; ebx = block/inode number
push ecx edx esi edi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
push eax eax
mov esi, .forward ; search forward, then backward
.test_block_group:
call extfsReadDescriptor
jc .fail
dec [eax+BGDESCR.blocksFree+ebx*2]
mov eax, [eax+BGDESCR.blockBitmap+ebx*4]
push ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
mov edx, eax
mov edi, ebx
call extfsReadBlock
pop ebx
jc .fail
mov ecx, [ebp+EXTFS.superblock.blocksPerGroup+ebx*8]
or eax, -1
shr ecx, 5
jz .next
repz scasd
jz .next
sub edi, 4
mov eax, [edi]
not eax
bsf eax, eax
bts [edi], eax
sub edi, [ebp+EXTFS.mainBlockBuffer]
shl edi, 3
add eax, edi
mov ecx, eax
mov eax, edx
push ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
pop ebx
jc .fail
mov eax, [esp]
mul [ebp+EXTFS.superblock.blocksPerGroup+ebx*8]
add eax, ecx
dec [ebp+EXTFS.superblock.blocksFree+ebx*4]
mov ebx, eax
pop eax
add esp, 4
call extfsWriteDescriptor
@@:
pop edi esi edx ecx
ret
.fail:
pop eax eax
movi eax, ERROR_DEVICE
jmp @b
.next:
jmp esi
.forward:
inc dword[esp]
mov eax, [esp]
mul [ebp+EXTFS.superblock.blocksPerGroup+ebx*8]
neg ebx
cmp eax, [ebp+EXTFS.superblock.blocksTotal+ebx*4]
ja @f
neg ebx
mov eax, [esp]
jmp .test_block_group
@@:
neg ebx
mov eax, [esp+4]
mov [esp], eax
mov esi, .backward
.backward:
sub dword[esp], 1
jc .fail
mov eax, [esp]
jmp .test_block_group
extfsGetFileBlock:
; in:
; ecx = file block number
; esi -> inode
; out:
; ecx = block number
test [esi+INODE.featureFlags], EXTENTS_USED
jz .listTreeSearch
pushad
add esi, INODE.blockNumbers
.extentTreeSearch:
cmp word [esi+NODEHEADER.magic], 0xF30A
jne .fail
movzx ebx, [esi+NODEHEADER.entriesFolow]
add esi, sizeof.NODEHEADER
cmp word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0
je .leaf_block
test ebx, ebx
jz .fail ; empty
@@:
cmp ebx, 1
je .end_search_index
cmp ecx, [esi+INDEX.fileBlock]
jb .fail
cmp ecx, [esi+sizeof.INDEX+INDEX.fileBlock]
jb .end_search_index
add esi, sizeof.INDEX
dec ebx
jmp @b
.end_search_index:
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov eax, [esi+INDEX.nodeBlock]
call extfsReadBlock
jc .fail
mov esi, ebx
jmp .extentTreeSearch
.leaf_block:
test ebx, ebx
jz .fail
mov edx, [esi+EXTENT.fileBlock]
cmp ecx, edx
jb .fail
movzx edi, [esi+EXTENT.blocksCount]
add edx, edi
cmp ecx, edx
jb .end_search_extent
add esi, sizeof.EXTENT
dec ebx
jmp .leaf_block
.end_search_extent:
sub ecx, [esi+EXTENT.fileBlock]
add ecx, [esi+EXTENT.fsBlock]
mov PUSHAD_ECX, ecx
popad
xor eax, eax
ret
.fail:
popad
movi eax, ERROR_FS_FAIL
stc
ret
.get_indirect_block:
push edx ebx
mov eax, [esi+INODE.addressBlock]
test eax, eax
jz .fail3
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc @f
mov ecx, [ebx+ecx*4]
@@:
pop ebx edx
ret
.get_direct_block:
mov ecx, [esi+INODE.blockNumbers+ecx*4]
xor eax, eax
ret
.listTreeSearch:
cmp ecx, 12
jb .get_direct_block
sub ecx, 12
cmp ecx, [ebp+EXTFS.dwordsPerBlock]
jb .get_indirect_block
sub ecx, [ebp+EXTFS.dwordsPerBlock]
cmp ecx, [ebp+EXTFS.dwordsPerBranch]
jb .get_double_indirect_block
; triply-indirect blocks
sub ecx, [ebp+EXTFS.dwordsPerBranch]
push edx ebx
mov eax, [esi+INODE.tripleAddress]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
xor edx, edx
mov eax, ecx
div [ebp+EXTFS.dwordsPerBranch]
; eax = number in triply-indirect block, edx = number in branch
mov eax, [ebx+eax*4]
test eax, eax
jz .fail3
call extfsReadBlock
jc .fail2
mov eax, edx
jmp @f
.fail3:
pop ebx edx
movi eax, ERROR_FS_FAIL
stc
ret
.get_double_indirect_block:
push edx ebx
mov eax, [esi+INODE.doubleAddress]
test eax, eax
jz .fail3
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov eax, ecx
@@:
xor edx, edx
div [ebp+EXTFS.dwordsPerBlock]
; eax = number in doubly-indirect block, edx = number in indirect block
mov eax, [ebx+eax*4]
test eax, eax
jz .fail3
call extfsReadBlock
jc .fail2
mov ecx, [ebx+edx*4]
.fail2:
pop ebx edx
ret
extfsSetFileBlock:
; in:
; ecx = file block number
; edi = block number
; esi -> inode
push ebx ecx edx
cmp ecx, 12
jb .direct_block
sub ecx, 12
cmp ecx, [ebp+EXTFS.dwordsPerBlock]
jb .indirect_block
sub ecx, [ebp+EXTFS.dwordsPerBlock]
cmp ecx, [ebp+EXTFS.dwordsPerBranch]
jb .double_indirect_block
; triple indirect blocks
sub ecx, [ebp+EXTFS.dwordsPerBranch]
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jnz @f
call inodeBlockAlloc
jc .ret
mov [esi+INODE.tripleAddress], ebx
mov eax, ebx
@@:
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_alloc_4
xor edx, edx
mov eax, ecx
div [ebp+EXTFS.dwordsPerBranch]
; eax = number in triply-indirect block, edx = number in branch
lea ecx, [ebx+eax*4]
mov eax, [ebx+eax*4]
test eax, eax
jnz @f
call inodeBlockAlloc
jc .fail_alloc_4
mov [ecx], ebx
mov eax, [esp]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc .fail_alloc_4
mov eax, [ecx]
@@:
mov [esp], eax
call extfsReadBlock
jc .fail_alloc_4
mov eax, edx
jmp @f
.double_indirect_block:
mov eax, [esi+INODE.doubleAddress]
test eax, eax
jnz .double_indirect_present
call inodeBlockAlloc
jc .ret
mov [esi+INODE.doubleAddress], ebx
mov eax, ebx
.double_indirect_present:
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_alloc_4
mov eax, ecx
@@:
xor edx, edx
div [ebp+EXTFS.dwordsPerBlock]
; eax = number in doubly-indirect block, edx = number in indirect block
lea ecx, [ebx+edx*4]
push ecx
lea ecx, [ebx+eax*4]
cmp dword[ecx], 0
jne @f
call inodeBlockAlloc
jc .fail_alloc_8
mov [ecx], ebx
mov eax, [esp+4]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc .fail_alloc_8
@@:
mov eax, [ecx]
push eax
call extfsReadBlock
jc .fail_alloc_12
pop eax ecx edx
mov [ecx], edi
call extfsWriteBlock
jmp .ret
.indirect_block:
mov eax, [esi+INODE.addressBlock]
test eax, eax
jnz @f
call inodeBlockAlloc
jc .ret
mov [esi+INODE.addressBlock], ebx
mov eax, ebx
@@:
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_alloc_4
mov [ebx+ecx*4], edi
pop eax
call extfsWriteBlock
jmp .ret
.direct_block:
mov [esi+INODE.blockNumbers+ecx*4], edi
xor eax, eax
.ret:
pop edx ecx ebx
ret
.fail_alloc_12:
pop ebx
.fail_alloc_8:
pop ebx
.fail_alloc_4:
pop ebx
jmp .ret
extfsEraseFileBlock: ; also allocates
; in:
; edx = inode number
; eax = file block number
; [ebp+EXTFS.tempInodeBuffer] = inode
push ebx ecx edx edi esi
mov edi, eax
mov ecx, eax
lea esi, [ebp+EXTFS.tempInodeBuffer]
call extfsGetFileBlock
jc @f
test ecx, ecx
jz .allocate
mov edx, ecx
mov ecx, [ebp+EXTFS.bytesPerBlock]
mov edi, [ebp+EXTFS.tempBlockBuffer]
xor eax, eax
rep stosb
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jmp @f
.allocate:
mov eax, edx
call extfsBlockAlloc
jc @f
mov ecx, edi
mov edi, ebx
lea esi, [ebp+EXTFS.tempInodeBuffer]
call extfsSetFileBlock
jc @f
mov eax, [ebp+EXTFS.sectorsPerBlock]
add [esi+INODE.sectorsUsed], eax
xor eax, eax
@@:
pop esi edi edx ecx ebx
ret
extfsFreeFileBlock:
; in:
; eax = file block number
; [ebp+EXTFS.tempInodeBuffer] = inode
push ebx ecx edi esi
mov edi, eax
mov ecx, eax
lea esi, [ebp+EXTFS.tempInodeBuffer]
call extfsGetFileBlock
jc @f
test ecx, ecx
jz @f
mov eax, ecx
xor ecx, ecx
call extfsResourceFree
mov ecx, edi
xor edi, edi
lea esi, [ebp+EXTFS.tempInodeBuffer]
call extfsSetFileBlock
mov eax, [ebp+EXTFS.sectorsPerBlock]
sub [esi+INODE.sectorsUsed], eax
xor eax, eax
@@:
pop esi edi ecx ebx
ret
extfsReadFileBlock:
; in:
; eax = file block number
; [ebp+EXTFS.tempInodeBuffer] = inode
; out:
; [ebp+EXTFS.mainBlockBuffer] -> block
push ebx ecx edx esi
mov ecx, eax
lea esi, [ebp+EXTFS.tempInodeBuffer]
call extfsGetFileBlock
jc .ret
test ecx, ecx
jz @f
mov eax, ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
.ret:
pop esi edx ecx ebx
ret
@@:
movi eax, ERROR_FS_FAIL
stc
jmp .ret
extfsWriteFileBlock:
; in:
; eax = file block number
; [ebp+EXTFS.tempInodeBuffer] = inode
; [ebp+EXTFS.mainBlockBuffer] -> block to write
push ebx ecx edx esi
mov ecx, eax
lea esi, [ebp+EXTFS.tempInodeBuffer]
call extfsGetFileBlock
jc @f
test ecx, ecx
jz @b
mov eax, ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
@@:
pop esi edx ecx ebx
ret
getInodeLocation:
; in: eax = inode number
; out:
; ebx = inode sector
; edx = offset in sector
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ecx, edx
shl eax, 5
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
add eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc @f
add ebx, edx
mov ebx, [ebx+BGDESCR.inodeTable]
mov eax, ecx
mov ecx, [ebp+EXTFS.sectorsPerBlockLog]
shl ebx, cl
mul [ebp+EXTFS.superblock.inodeSize]
mov edx, eax
shr eax, 9
and edx, 511
add ebx, eax
xor eax, eax
@@:
ret
writeInode:
; in:
; eax = inode number
; ebx -> inode data
push edx edi esi ecx ebx eax
mov edi, ebx
call fsGetTime
add eax, 978307200
mov [edi+INODE.inodeModified], eax
pop eax
call getInodeLocation
jc .ret
mov eax, ebx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call fs_read32_sys
test eax, eax
jnz @f
mov eax, ecx
mov esi, edi
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edi, edx
add edi, ebx
rep movsb
call fs_write32_sys
.ret:
pop ebx ecx esi edi edx
ret
@@:
movi eax, ERROR_DEVICE
stc
jmp .ret
readInode:
; in:
; eax = inode number
; ebx -> inode buffer
push edx edi esi ecx ebx
mov edi, ebx
call getInodeLocation
jc @f
mov eax, ebx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call fs_read32_sys
test eax, eax
jnz @b
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov esi, edx
add esi, ebx
rep movsb
xor eax, eax
@@:
pop ebx ecx esi edi edx
ret
extfsExtendFile:
; in:
; eax = inode number
; ecx = new size
push ebx ecx edx esi edi eax
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode
jc .ret
cmp [ebx+INODE.fileSize], ecx
jnc .ret
mov eax, [ebx+INODE.fileSize]
push eax
sub ecx, eax
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .start_aligned
mov esi, [ebp+EXTFS.bytesPerBlock]
sub esi, edx
cmp esi, ecx
jbe @f
mov esi, ecx
@@: ; clear esi trailing bytes in block number eax
push eax
call extfsReadFileBlock
pop edi
jc .error_inode_size
push edi ecx
xor eax, eax
mov ecx, esi
mov edi, ebx
add edi, edx
rep stosb
pop ecx eax
call extfsWriteFileBlock
jc .error_inode_size
add [esp], esi
sub ecx, esi
jz .write_inode
.start_aligned:
cmp ecx, [ebp+EXTFS.bytesPerBlock]
jb @f
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
mov edx, [esp+4]
call extfsEraseFileBlock
jc .error_inode_size
mov eax, [ebp+EXTFS.bytesPerBlock]
sub ecx, eax
add [esp], eax
jmp .start_aligned
@@: ; handle the remaining bytes
test ecx, ecx
jz .write_inode
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
mov edx, [esp+4]
call extfsEraseFileBlock
jc .error_inode_size
add [esp], ecx
.write_inode:
xor eax, eax
.error_inode_size:
lea ebx, [ebp+EXTFS.tempInodeBuffer]
pop [ebx+INODE.fileSize]
push eax
mov eax, [esp+4]
call writeInode
pop ebx
jc .ret
xchg eax, ebx
cmp ebx, eax ; set CF
.ret:
pop edi edi esi edx ecx ebx
ret
extfsTruncateFile:
; in:
; eax = inode number
; ecx = new size
push ebx ecx edx esi edi eax
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode
jc .ret
cmp ecx, [ebx+INODE.fileSize]
jnc .ret
mov eax, [ebx+INODE.fileSize]
push eax
sub ecx, eax
not ecx
inc ecx
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .start_aligned
mov esi, edx
cmp esi, ecx
jbe @f
; if the size to truncate is smaller than the unaligned bytes
; we're going to clear neccessary bytes from the EOF
push eax
call extfsReadFileBlock
pop edi
jc .error_inode_size
push edi ecx
mov edi, [ebp+EXTFS.mainBlockBuffer]
sub edx, ecx
add edi, edx
xor eax, eax
rep stosb
pop ecx eax
call extfsWriteFileBlock
jc .error_inode_size
sub [esp], ecx
jmp .write_inode
@@:
call extfsFreeFileBlock
sub [esp], esi
sub ecx, esi
jz .write_inode
.start_aligned:
cmp ecx, [ebp+EXTFS.bytesPerBlock]
jb @f
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
dec eax
call extfsFreeFileBlock
mov eax, [ebp+EXTFS.bytesPerBlock]
sub ecx, eax
sub [esp], eax
jmp .start_aligned
@@: ; handle the remaining bytes
test ecx, ecx
jz .write_inode
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
dec eax
push eax
call extfsReadFileBlock
pop edi
jc .error_inode_size
push edi ecx
mov edi, [ebp+EXTFS.mainBlockBuffer]
mov edx, [ebp+EXTFS.bytesPerBlock]
sub edx, ecx
add edi, edx
xor eax, eax
rep stosb
pop ecx eax
call extfsWriteFileBlock
jc .error_inode_size
sub [esp], ecx
.write_inode:
xor eax, eax
.error_inode_size:
lea ebx, [ebp+EXTFS.tempInodeBuffer]
pop [ebx+INODE.fileSize]
push eax
mov eax, [esp+4]
call writeInode
pop ebx
jc .ret
xchg eax, ebx
cmp ebx, eax ; set CF
.ret:
pop edi edi esi edx ecx ebx
ret
linkInode:
; in:
; eax = inode on which to link
; ebx = inode to link
; esi -> name in UTF-8
; dl = file type
push esi edi ebx ecx eax edx
call strlen
add ecx, 8 ; directory entry size
push esi ebx ecx
xor ecx, ecx
lea esi, [ebp+EXTFS.tempInodeBuffer]
mov ebx, esi
call readInode
jc .error_inode_read
mov ecx, [ebp+EXTFS.sectorsPerBlockLog]
mov eax, [esi+INODE.sectorsUsed]
shr eax, cl
xor ecx, ecx
push eax ; maximum file block number
push ecx ; current file block number
.searchBlock:
call extfsGetFileBlock
jc .error_get_inode_block
test ecx, ecx
jz .alloc_block
push ecx
mov eax, ecx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error_block_read
mov ecx, [esp+8]
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov edx, edi
add edx, [ebp+EXTFS.bytesPerBlock]
.searchSpace:
movzx eax, [edi+DIRENTRY.entryLength]
test eax, eax
jz .zeroLength
cmp [edi+DIRENTRY.inodeNumber], 0
je .unusedEntry
movzx ebx, [edi+DIRENTRY.nameLength]
add ebx, 8+3
and ebx, -4
sub eax, ebx
add edi, ebx
cmp eax, ecx
jb .nextEntry
sub edi, ebx
mov [edi+DIRENTRY.entryLength], bx
add edi, ebx
mov [edi+DIRENTRY.entryLength], ax
jmp .found
.unusedEntry:
cmp eax, ecx
jge .found
.nextEntry:
add edi, eax
cmp edi, edx
jb .searchSpace
jmp .nextBlock
.zeroLength:
mov [edi+DIRENTRY.entryLength], cx
mov eax, edx
sub eax, edi
cmp eax, ecx
jge .found
mov [edi+DIRENTRY.inodeNumber], 0
mov [edi+DIRENTRY.entryLength], ax
; this block wasn't linking to the next one, so write it, and use the next block
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc .error_get_inode_block
inc dword[esp]
mov ecx, [esp]
call extfsGetFileBlock
jc .error_get_inode_block
test ecx, ecx
jz .alloc_block
push ecx
jmp .prepare_block
.nextBlock:
add esp, 4
inc dword[esp]
mov ecx, [esp]
cmp ecx, [esp+4]
jbe .searchBlock
.alloc_block:
mov eax, [esp+12]
call extfsBlockAlloc
jc .error_get_inode_block
mov ecx, [esp]
mov edi, ebx
call extfsSetFileBlock
jc .error_get_inode_block
mov eax, [ebp+EXTFS.bytesPerBlock]
add [esi+INODE.fileSize], eax
mov eax, [ebp+EXTFS.sectorsPerBlock]
add [esi+INODE.sectorsUsed], eax
mov eax, [esp+24]
mov ebx, esi
call writeInode
jc .error_get_inode_block
push edi ; save the block we just allocated
.prepare_block:
mov eax, [esp]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error_block_read
mov edi, ebx
mov eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+DIRENTRY.entryLength], ax
.found:
pop edx ecx ecx ecx ebx esi
push ebx
mov [edi], ebx ; save inode
mov eax, [esp+4]
cmp [ebp+EXTFS.superblock.dynamicVersionFlag], 0
je .name
mov [edi+DIRENTRY.fileType], al
.name:
sub ecx, 8
mov [edi+DIRENTRY.nameLength], cl
add edi, 8
rep movsb
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc .error_block_write
mov eax, [esp]
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode
jc .error_block_write
pop eax
inc [ebx+INODE.linksCount]
call writeInode
jc @f
xor eax, eax
@@:
pop edx ecx ecx ebx edi esi
ret
.error_block_read:
pop ebx
.error_get_inode_block:
pop ebx ebx
.error_inode_read:
pop ebx ebx
.error_block_write:
pop ebx
jmp @b
unlinkInode:
; in:
; eax = inode from which to unlink
; ebx = inode to unlink
; out:
; eax = current number of links to inode, -1 = error
push edx ebx
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode
jc .fail
push eax
lea esi, [ebp+EXTFS.tempInodeBuffer]
.loop:
mov ecx, [esp]
call extfsGetFileBlock
jc .fail_loop
test ecx, ecx
jz .fail_loop
mov eax, ecx
mov edi, ecx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_loop
.first_dir_entry: ; edi -> block
mov eax, [esp+4]
cmp [ebx+DIRENTRY.inodeNumber], eax
jne @f
mov [ebx+DIRENTRY.inodeNumber], 0
mov word [ebx+DIRENTRY.nameLength], 0 ; fileType = 0
jmp .write_block
@@:
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, ebx
movzx ecx, [ebx+DIRENTRY.entryLength]
add ebx, ecx
.dir_entry:
cmp [ebx+DIRENTRY.inodeNumber], eax
jne @f
mov cx, [ebx+DIRENTRY.entryLength]
add [edx+DIRENTRY.entryLength], cx
pop eax
jmp .write_block
@@:
mov edx, ebx
movzx ecx, [ebx+DIRENTRY.entryLength]
test ecx, ecx
jz .fail_inode
add ebx, ecx
cmp ebx, [esp]
jb .dir_entry
pop ecx
inc dword[esp]
jmp .loop
.fail_inode:
pop eax
.fail_loop:
pop eax
.fail:
or eax, -1
jmp @f
.write_block:
pop eax
mov eax, edi
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc .fail
mov eax, [esp]
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode
jc .fail
dec word [ebx+INODE.linksCount]
mov eax, [esp]
call writeInode
jc .fail
movzx eax, word [ebx+INODE.linksCount]
@@:
pop ebx edx
ret
findInode:
; in: esi -> path string in UTF-8
; out:
; edi -> file name in UTF-8
; esi = last inode number
; [ebp+EXTFS.mainInodeBuffer] = last inode
; ecx = parent inode number
; CF=1 -> file not found, edi=0 -> error
push esi
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.mainInodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edx, esi
rep movsb
pop esi
pushd 0 ROOT_INODE
cmp [edx+INODE.sectorsUsed], 0
jz .not_found
cmp byte [esi], 0
jnz .next_path_part
xor eax, eax
mov edi, esi
pop esi ecx
ret
@@:
pop esi esi
.error:
pop esi ecx
xor edi, edi
stc
ret
.next_path_part:
push [edx+INODE.sectorsUsed]
xor ecx, ecx
.folder_block_cycle:
push ecx
xchg esi, edx
call extfsGetFileBlock
jc @b
xchg esi, edx
mov eax, ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc @b
push esi edx
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
.start_rec:
cmp [ebx+DIRENTRY.inodeNumber], 0
jz .next_rec
push esi
movzx ecx, [ebx+DIRENTRY.nameLength]
lea edi, [ebx+DIRENTRY.name]
repz cmpsb
jz .test_find
@@: ; doesn't match
pop esi
.next_rec:
movzx eax, [ebx+DIRENTRY.entryLength]
add ebx, eax
cmp ebx, edx
jb .start_rec
push eax
jmp @f
.test_find:
cmp byte [esi], 0
je @f
cmp byte [esi], '/'
jne @b
inc esi
@@:
pop edx edx edi ecx eax
; ebx -> matched directory entry, esi -> name without parent, or not changed
cmp edi, esi
jnz @f
sub eax, [ebp+EXTFS.sectorsPerBlock]
jle .not_found
push eax
inc ecx
jmp .folder_block_cycle
@@:
pop eax
mov [esp], eax
mov eax, [ebx+DIRENTRY.inodeNumber]
lea ebx, [ebp+EXTFS.mainInodeBuffer]
push eax
call readInode
jc .error
cmp byte [esi], 0
je .ret
mov edx, ebx
movzx eax, [ebx+INODE.accessMode]
and eax, TYPE_MASK
cmp eax, DIRECTORY
jz .next_path_part
xor edi, edi ; path folder is a file
.not_found:
movi eax, ERROR_FILE_NOT_FOUND
stc
.ret:
pop esi ecx
ret
writeSuperblock:
push ebx
mov eax, 2
lea ebx, [ebp+EXTFS.superblock]
call fs_write32_sys
pop ebx
ret
extfsWritingInit:
movi eax, ERROR_ACCESS_DENIED
cmp byte [esi], 0
jz @f
movi eax, ERROR_UNSUPPORTED_FS
test [ebp+EXTFS.mountType], READ_ONLY
jnz @f
ext_lock:
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_lock
@@:
pop ebx
xor ebx, ebx
ret
ext_unlock:
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_unlock
;----------------------------------------------------------------
ext_ReadFolder:
call ext_lock
cmp byte [esi], 0
jz .root_folder
push ebx
call findInode
pop ebx
jc .error_ret
lea esi, [ebp+EXTFS.mainInodeBuffer]
test [esi+INODE.accessMode], FLAG_FILE
jnz .error_not_found
jmp @f
.root_folder:
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.mainInodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
shr ecx, 2
push edi
rep movsd
pop esi
@@:
cmp [esi+INODE.fileSize], 0
je .error_empty_dir
mov edx, [ebx+16]
push edx ; [edi+28] result buffer
push 0 ; [edi+24] end of the current block in folder
pushd [ebx+12] ; [edi+20] files to read
pushd [ebx+4] ; [edi+16] first wanted file
pushd [ebx+8] ; [edi+12] flags
push 0 ; [edi+8] read files
push 0 ; [edi+4] files in folder
push 0 ; [edi] current block index
mov edi, esp ; edi -> local variables
add edx, 32
xor ecx, ecx
call extfsGetFileBlock
jc .error_get_block
mov eax, ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_get_block
mov eax, ebx
add eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+24], eax
mov ecx, [edi+16]
.find_wanted_start:
jecxz .find_wanted_end
.find_wanted_cycle:
cmp [ebx+DIRENTRY.inodeNumber], 0
jz @f
inc dword [edi+4]
dec ecx
@@:
movzx eax, [ebx+DIRENTRY.entryLength]
cmp eax, 12 ; minimum entry length
jb .error_bad_len
test eax, 3 ; length must be aligned
jnz .error_bad_len
sub [esi+INODE.fileSize], eax
add ebx, eax
cmp ebx, [edi+24]
jb .find_wanted_start
push .find_wanted_start
.end_block: ; read next block
cmp [esi+INODE.fileSize], 0
jle .end_dir
inc dword [edi]
push ecx
mov ecx, [edi]
call extfsGetFileBlock
jc .error_get_block
mov eax, ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_get_block
pop ecx
mov eax, ebx
add eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+24], eax
ret
.wanted_end:
loop .find_wanted_cycle
.find_wanted_end:
mov ecx, [edi+20]
.wanted_start:
jecxz .wanted_end
cmp [ebx+DIRENTRY.inodeNumber], 0
jz .empty_rec
inc dword [edi+8]
inc dword [edi+4]
push ebx edi ecx esi edx
pushd [edi+12]
mov edi, edx
xor eax, eax
mov ecx, 40 / 4
rep stosd
popd [edx+4]
mov eax, [ebx+DIRENTRY.inodeNumber]
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode
jc .error_read_subinode
mov esi, ebx
lea edi, [edx+8]
mov eax, [ebx+INODE.inodeModified]
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
mov eax, [esi+INODE.accessedTime]
sub eax, 978307200
call fsTime2bdfe
mov eax, [esi+INODE.dataModified]
sub eax, 978307200
call fsTime2bdfe
pop edx
or dword [edx], KOS_DIRECTORY
test [esi+INODE.accessMode], FLAG_FILE
jz @f
xor dword [edx], KOS_DIRECTORY ; mark as file
mov eax, [esi+INODE.fileSize]
stosd
mov eax, [esi+INODE.fileSizeHigh]
stosd
@@:
mov esi, [esp+12]
movzx ecx, [esi+DIRENTRY.nameLength]
lea esi, [esi+DIRENTRY.name]
add ecx, esi
cmp byte [esi], '.'
jnz @f
or byte [edx], KOS_HIDDEN
@@:
lea edi, [edx+40]
cmp byte [edx+4], 1
jz .utf16
@@:
call utf8to16
call uni2ansi_char
stosb
cmp esi, ecx
jc @b
and byte [edi], 0
add edx, 40+264
@@:
pop esi ecx edi ebx
dec ecx
.empty_rec:
movzx eax, [ebx+DIRENTRY.entryLength]
cmp eax, 12
jb .error_bad_len
test eax, 3
jnz .error_bad_len
sub [esi+INODE.fileSize], eax
add ebx, eax
cmp ebx, [edi+24]
jb .wanted_start
push .wanted_start
jmp .end_block
.utf16:
call utf8to16
stosw
cmp esi, ecx
jc .utf16
and word [edi], 0
add edx, 40+520
jmp @b
.end_dir:
call ext_unlock
mov edx, [edi+28]
mov ebx, [edi+8]
mov ecx, [edi+4]
mov dword [edx], 1 ; version
mov [edx+4], ebx
mov [edx+8], ecx
lea esp, [edi+32]
mov ecx, 20/4
lea edi, [edx+12]
xor eax, eax
rep stosd
ret
.error_bad_len:
movi eax, ERROR_FS_FAIL
.error_read_subinode:
.error_get_block:
lea esp, [edi+32]
.error_ret:
or ebx, -1
push eax
call ext_unlock
pop eax
ret
.error_empty_dir:
movi eax, ERROR_FS_FAIL
jmp .error_ret
.error_not_found:
movi eax, ERROR_FILE_NOT_FOUND
jmp .error_ret
;----------------------------------------------------------------
ext_ReadFile:
call ext_lock
push ERROR_ACCESS_DENIED
cmp byte [esi], 0
jz .error ; root
mov [esp], ebx
call findInode
pop ebx
jc .error_eax
push ERROR_ACCESS_DENIED
lea esi, [ebp+EXTFS.mainInodeBuffer]
mov ax, [esi+INODE.accessMode]
and ax, TYPE_MASK
cmp ax, FLAG_FILE
jnz .error ; not a file
pop eax
mov edi, [ebx+16]
mov ecx, [ebx+12]
mov eax, [ebx+4]
mov edx, [ebx+8]
push ERROR_END_OF_FILE
cmp [esi+INODE.fileSizeHigh], edx
ja @f
jb .error
cmp [esi+INODE.fileSize], eax
jna .error
@@:
add esp, 4
add eax, ecx
adc edx, 0
cmp [esi+INODE.fileSizeHigh], edx
ja .read_till_requested
jb .read_whole_file
cmp [esi+INODE.fileSize], eax
jae .read_till_requested
.read_whole_file:
push 1 ; read till the end of file
mov ecx, [esi+INODE.fileSize]
sub ecx, [ebx+4]
jmp @f
.read_till_requested:
push 0 ; read as much as requested
@@: ; ecx = bytes to read, edi -> buffer
push ecx
; read part of the first block
mov edx, [ebx+8]
mov eax, [ebx+4]
div [ebp+EXTFS.bytesPerBlock]
push eax
push ecx
mov ecx, eax
call extfsGetFileBlock
jc .error_at_first_block
mov ebx, [ebp+EXTFS.mainBlockBuffer]
mov eax, ecx
call extfsReadBlock
jc .error_at_first_block
pop ecx
add ebx, edx
neg edx
add edx, [ebp+EXTFS.bytesPerBlock]
cmp ecx, edx
jbe .only_one_block
mov eax, ecx
sub eax, edx ; bytes to read
mov ecx, edx
push esi
mov esi, ebx
rep movsb
pop esi
mov ebx, edi
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
mov edi, eax
@@:
test edi, edi
jz .finish_block
inc dword [esp]
mov ecx, [esp]
call extfsGetFileBlock
jc .error_at_read_cycle
mov eax, ecx
call extfsReadBlock
jc .error_at_read_cycle
add ebx, [ebp+EXTFS.bytesPerBlock]
dec edi
jmp @b
.finish_block: ; edx = number of bytes in the last block
test edx, edx
jz .end_read
pop ecx ; block counter
inc ecx
call extfsGetFileBlock
jc .error_at_finish_block
mov edi, ebx
mov eax, ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_at_finish_block
push eax
mov ecx, edx
.only_one_block:
mov esi, ebx
rep movsb
.end_read:
call ext_unlock
pop eax ebx eax
test eax, eax
jz @f
movi eax, ERROR_END_OF_FILE
@@:
ret
.error_at_first_block:
pop ebx
.error_at_read_cycle:
pop ebx
.error_at_finish_block:
pop ebx ebx
.error_eax:
push eax
.error:
call ext_unlock
xor ebx, ebx
pop eax
ret
;----------------------------------------------------------------
ext_GetFileInfo:
call ext_lock
mov edx, [ebx+16]
cmp byte [esi], 0
jz .is_root
push edx
call findInode
pop edx
lea esi, [ebp+EXTFS.mainInodeBuffer]
jnc @f
push eax
call ext_unlock
pop eax
ret
.is_root:
mov edi, esi
lea esi, [ebp+EXTFS.rootInodeBuffer]
@@:
mov bl, [edi]
xor eax, eax
mov edi, edx
mov ecx, 40/4
rep stosd
cmp bl, '.'
jne @f
or dword [edx], KOS_HIDDEN
@@:
or dword [edx], KOS_DIRECTORY
test [esi+INODE.accessMode], FLAG_FILE
jz @f
xor dword [edx], KOS_DIRECTORY ; mark as file
mov eax, [esi+INODE.fileSize]
mov ebx, [esi+INODE.fileSizeHigh]
mov dword [edx+32], eax
mov dword [edx+36], ebx
@@:
lea edi, [edx+8]
mov eax, [esi+INODE.inodeModified]
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
mov eax, [esi+INODE.accessedTime]
sub eax, 978307200
call fsTime2bdfe
mov eax, [esi+INODE.dataModified]
sub eax, 978307200
call fsTime2bdfe
call ext_unlock
xor eax, eax
ret
;----------------------------------------------------------------
ext_SetFileInfo:
call extfsWritingInit
pushd [ebx+16]
call findInode
pop edx
jc @f
push esi ; inode number
lea esi, [edx+16]
lea edi, [ebp+EXTFS.mainInodeBuffer]
call fsCalculateTime
add eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
mov [edi+INODE.accessedTime], eax
add esi, 8
call fsCalculateTime
add eax, 978307200
mov [edi+INODE.dataModified], eax
mov ebx, edi
pop eax
call writeInode
@@:
push eax
jc @f
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
@@:
call ext_unlock
pop eax
ret
;----------------------------------------------------------------
ext_Delete:
call extfsWritingInit
call findInode
mov ebx, esi
push eax
jc .ret
pop eax
lea edx, [ebp+EXTFS.mainInodeBuffer]
movzx edx, [edx+INODE.accessMode]
and edx, TYPE_MASK
cmp edx, DIRECTORY
jne .file
push ebx ecx edx 0
lea esi, [ebp+EXTFS.mainInodeBuffer]
.checkDirectory:
mov ecx, [esp]
call extfsGetFileBlock
jc .not_empty_eax
test ecx, ecx
jz .empty
mov eax, ecx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .not_empty_eax
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
movzx ecx, [ebx+DIRENTRY.entryLength]
add ebx, ecx
.dir_entry:
cmp byte [ebx+DIRENTRY.nameLength], 1
jne @f
cmp byte [ebx+DIRENTRY.name], '.'
jne .not_empty
@@:
cmp byte [ebx+DIRENTRY.nameLength], 2
jne .not_empty
cmp word [ebx+DIRENTRY.name], '..'
jne .not_empty
movzx ecx, [ebx+DIRENTRY.entryLength]
add ebx, ecx
cmp ebx, edx
jb .dir_entry
inc dword[esp]
jmp .checkDirectory
.empty:
pop edx edx ecx ebx
.file:
mov eax, ecx
push ebx ecx
call unlinkInode
cmp eax, -1
je .error_stack8
pop ebx
test eax, eax
jz @f
xor eax, eax
cmp edx, DIRECTORY
jnz .error_stack4_eax ; hardlinks
mov eax, [esp]
call unlinkInode
@@:
mov eax, [esp]
lea ebx, [ebp+EXTFS.mainInodeBuffer]
call readInode
jc .error_stack4_eax
; free file's data
lea esi, [ebp+EXTFS.mainInodeBuffer]
xor ecx, ecx
@@:
push ecx
call extfsGetFileBlock
jc .error_stack8_eax
mov eax, ecx
test eax, eax
jz @f
xor ecx, ecx
call extfsResourceFree
pop ecx
inc ecx
jmp @b
@@: ; free indirect blocks
pop ecx
push edx
lea edi, [ebp+EXTFS.mainInodeBuffer]
mov eax, [edi+INODE.addressBlock]
test eax, eax
jz .success
xor ecx, ecx
call extfsResourceFree
mov eax, [edi+INODE.doubleAddress]
call freeDoublyIndirectBlock
cmp eax, 1
je .success
mov eax, [edi+INODE.tripleAddress]
test eax, eax
jz .success
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
pop ecx
jc .error_stack8_eax
mov eax, ecx
xor ecx, ecx
call extfsResourceFree
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
@@:
mov eax, [ebx]
test eax, eax
jz .success
push ebx edx
call freeDoublyIndirectBlock
pop edx ebx
cmp eax, 1
je .success
add ebx, 4
cmp ebx, edx
jb @b
.success: ; clear the inode, and add deletion time
xor eax, eax
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
rep stosb
lea edi, [ebp+EXTFS.mainInodeBuffer]
call fsGetTime
pop edx
add eax, 978307200
mov [edi+INODE.deletedTime], eax
mov eax, [esp]
mov ebx, edi
call writeInode
jc .error_stack4_eax
cmp edx, DIRECTORY
jne @f
mov eax, [esp]
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
push eax
call extfsReadDescriptor
jc .error_stack8
dec [eax+BGDESCR.directoriesCount]
pop eax
call extfsWriteDescriptor
@@: ; free inode
pop eax
dec eax
xor ecx, ecx
inc ecx
call extfsResourceFree
push eax
.disk_sync:
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
xor ebx, ebx
pop eax
ret
.not_empty:
pop eax
.error_stack8:
pop eax eax
push ERROR_ACCESS_DENIED
jmp .disk_sync
.not_empty_eax:
pop ebx
.error_stack8_eax:
pop ebx
.error_stack4_eax:
pop ebx
.error:
push eax
jmp .disk_sync
;----------------------------------------------------------------
ext_CreateFolder:
call extfsWritingInit
call findInode
jnc .success ; exist
test edi, edi
jz .error
mov eax, esi
xor ebx, ebx
inc ebx
call extfsResourceAlloc
jc .error
inc ebx
push ebx esi edi
xor al, al
lea edi, [ebp+EXTFS.tempInodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
rep stosb
lea edi, [ebp+EXTFS.tempInodeBuffer]
call fsGetTime
add eax, 978307200
mov [edi+INODE.accessedTime], eax
mov [edi+INODE.dataModified], eax
mov ebx, edi
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], DIRECTORY or PERMISSIONS
mov eax, edx
call writeInode
jc .error
; link to self
push edx esi
mov eax, edx
mov ebx, eax
mov dl, DIR_DIRECTORY
mov esi, self_link
call linkInode
pop esi edx
jc .error
; link to parent
push edx esi
mov eax, ebx
mov ebx, esi
mov dl, DIR_DIRECTORY
mov esi, parent_link
call linkInode
pop esi edx
jc .error
; link parent to child
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, DIR_DIRECTORY
call linkInode
jc .error
mov eax, ebx
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov edx, eax
call extfsReadDescriptor
jc @f
inc [eax+BGDESCR.directoriesCount]
mov eax, edx
call extfsWriteDescriptor
.success:
.error:
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
pop eax
ret
@@:
movi eax, ERROR_DEVICE
jmp .error
self_link db ".", 0
parent_link db "..", 0
;----------------------------------------------------------------
ext_CreateFile:
call extfsWritingInit
push 0 ebx
call findInode
jnc .exist
test edi, edi
jz .error
mov eax, esi
xor ebx, ebx
inc ebx
call extfsResourceAlloc
jc .error
inc ebx
push ebx ebx esi edi
xor al, al
lea edi, [ebp+EXTFS.tempInodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
rep stosb
lea edi, [ebp+EXTFS.tempInodeBuffer]
call fsGetTime
add eax, 978307200
mov [edi+INODE.accessedTime], eax
mov [edi+INODE.dataModified], eax
mov ebx, edi
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], FLAG_FILE or PERMISSIONS
mov eax, edx
call writeInode
jc .error2
; link parent to child
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, DIR_FLAG_FILE
call linkInode
jc .error2
pop esi ebx
push ebx esi
mov ecx, [ebx+12]
jmp ext_WriteFile.start
.exist:
lea edx, [ebp+EXTFS.mainInodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edx+INODE.accessMode], FLAG_FILE
jz .error ; not a file
pop ebx
push ebx esi
mov eax, esi
mov ecx, [ebx+12]
call extfsTruncateFile
jnc ext_WriteFile.start
.error2:
pop ebx
.error:
push eax
call ext_unlock
pop eax ebx ebx
xor ebx, ebx
ret
;----------------------------------------------------------------
ext_WriteFile:
call extfsWritingInit
push 0 ebx
call findInode
pop ebx
push ebx esi
jc .error
lea edx, [ebp+EXTFS.mainInodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edx+INODE.accessMode], FLAG_FILE
jz .error ; not a file
mov ecx, [ebx+4]
add ecx, [ebx+12]
.start:
mov eax, esi
call extfsExtendFile
jc .error
mov eax, [ebx+4]
mov ecx, [ebx+12]
mov esi, [ebx+16]
push eax
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .start_aligned
mov ebx, [ebp+EXTFS.bytesPerBlock]
sub ebx, edx
cmp ebx, ecx
jbe @f
mov ebx, ecx
@@:
push eax
call extfsReadFileBlock
pop edi
jc .error_inode_size
mov eax, edi
push ecx
mov ecx, ebx
mov edi, ebx
add edi, edx
rep movsb
pop ecx
call extfsWriteFileBlock
jc .error_inode_size
add [esp], ebx
sub ecx, ebx
jz .write_inode
.start_aligned:
cmp ecx, [ebp+EXTFS.bytesPerBlock]
jb @f
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
mov edx, [esp+4]
push eax
call extfsEraseFileBlock
pop edi
jc .error_inode_size
mov eax, edi
push ecx
mov ecx, [ebp+EXTFS.bytesPerBlock]
mov edi, [ebp+EXTFS.mainBlockBuffer]
rep movsb
pop ecx
call extfsWriteFileBlock
jc .error_inode_size
mov eax, [ebp+EXTFS.bytesPerBlock]
sub ecx, eax
add [esp], eax
jmp .start_aligned
@@: ; Handle the remaining bytes.
test ecx, ecx
jz .write_inode
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
push eax
call extfsReadFileBlock
pop eax
jnc @f
mov edx, [esp+4]
push eax
call extfsEraseFileBlock
pop edi
jc .error_inode_size
mov eax, edi
@@:
push ecx
mov edi, [ebp+EXTFS.mainBlockBuffer]
rep movsb
pop ecx
call extfsWriteFileBlock
jc .error_inode_size
add [esp], ecx
xor ecx, ecx
.error_inode_size:
mov [esp+12], eax
.write_inode:
lea ebx, [ebp+EXTFS.tempInodeBuffer]
pop eax eax
call writeInode
pop ebx
mov ebx, [ebx+12]
sub ebx, ecx
test eax, eax
jz @f
mov [esp], eax
@@:
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
@@:
call ext_unlock
pop eax
ret
.error:
pop ebx ebx ebx
push eax
jmp @b
;----------------------------------------------------------------
ext_SetFileEnd:
call extfsWritingInit
pushd [ebx+4]
call findInode
pop ecx
jc @f
lea edx, [ebp+EXTFS.mainInodeBuffer]
movi eax, ERROR_ACCESS_DENIED
cmp [edx+INODE.accessMode], FLAG_FILE
jnz @f ; not a file
mov eax, esi
call extfsExtendFile
jc @f
mov eax, esi
call extfsTruncateFile
jc @f
mov eax, esi
lea ebx, [ebp+EXTFS.tempInodeBuffer]
call writeInode
@@:
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
pop eax
ret