kolibrios-fun/kernel/trunk/fs/ext.inc
pathoswithin ba50660e2b ext fs optimizing
git-svn-id: svn://kolibrios.org@6726 a494cfbc-eb01-0410-851d-a64ba20cac60
2016-11-18 14:43:26 +00:00

2595 lines
67 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ?
align0 rb 200h-EXTFS.align0
superblock SUPERBLOCK
align1 rb 400h-EXTFS.align1
rootInodeBuffer INODE
align2 rb 600h-EXTFS.align2
inodeBuffer INODE
align3 rb 800h-EXTFS.align3
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
movi eax, sizeof.EXTFS
call malloc
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:
mov eax, ebp
call free
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]
pop eax
jmp free
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 edx eax
call extfsReadDescriptor
jc .fail2
inc [eax+BGDESCR.blocksFree+ecx*2]
mov edx, [eax+BGDESCR.blockBitmap+ecx*4]
pop eax
call extfsWriteDescriptor
jc .fail
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail
pop eax
push edx
mov edx, eax
and edx, 31
shr eax, 5
shl eax, 2
add eax, [ebp+EXTFS.tempBlockBuffer]
btr [eax], edx
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc @f
inc [ebp+EXTFS.superblock.blocksFree+ecx*4]
@@:
xor eax, eax
pop edx ebx
ret
.fail2:
pop eax
.fail:
pop eax
jmp @b
extfsInodeAlloc:
; in: eax = parent inode number
; out: ebx = allocated 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.inodesFree]
js .next
mov edx, [eax+BGDESCR.inodeBitmap]
mov eax, [esp]
call extfsWriteDescriptor
jc .fail
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edi, ebx
call extfsReadBlock
jc .fail
mov ecx, [ebp+EXTFS.superblock.inodesPerGroup]
or eax, -1
shr ecx, 5
repz scasd
jz .next
sub edi, 4
mov eax, [edi]
not eax
bsf eax, eax
bts [edi], eax
sub edi, [ebp+EXTFS.tempBlockBuffer]
shl edi, 3
add eax, edi
mov ecx, eax
mov eax, edx
call extfsWriteBlock
jc .fail
pop eax
mul [ebp+EXTFS.superblock.inodesPerGroup]
add eax, ecx
dec [ebp+EXTFS.superblock.inodesFree]
mov ebx, eax
pop eax
xor eax, eax
@@:
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.inodesPerGroup]
cmp eax, [ebp+EXTFS.superblock.inodesTotal]
ja @f
mov eax, [esp]
jmp .test_block_group
@@:
mov eax, [esp+4]
mov [esp], eax
mov esi, .backward
.backward:
sub dword[esp], 1
jc .fail
mov eax, [esp]
jmp .test_block_group
extfsExtentAlloc:
; in:
; eax = parent inode number
; ecx = blocks max
; out:
; ebx = first block number
; ecx = blocks allocated
push edx esi edi ecx
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
push eax eax
.test_block_group:
call extfsReadDescriptor
jc .fail
dec [eax+BGDESCR.blocksFree]
js .next
mov eax, [eax+BGDESCR.blockBitmap]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
mov edi, ebx
call extfsReadBlock
jc .fail
mov ecx, [ebp+EXTFS.superblock.blocksPerGroup]
shr ecx, 5
or eax, -1
repz scasd
jz .next
mov esi, edi
sub esi, 4
push edx ecx
mov eax, [esi]
not eax
bsf ecx, eax
not eax
shr eax, cl
shl eax, cl
mov ebx, 32
bsf ebx, eax
sub ebx, ecx
mov eax, [esp+16]
cmp ebx, eax
jc @f
mov ebx, eax
@@:
xchg ebx, ecx
or eax, -1
shl eax, cl
not eax
xchg ebx, ecx
shl eax, cl
or [esi], eax
sub esi, [ebp+EXTFS.tempBlockBuffer]
shl esi, 3
add esi, ecx
mov eax, [esp+16]
sub eax, ebx
mov [esp+16], ebx
add ebx, ecx
pop ecx
test eax, eax
jz .done
cmp ebx, 32
jnz .done
jecxz .done
mov ebx, eax
shr eax, 5
inc eax
and ebx, 31
cmp ecx, eax
jnc @f
mov eax, ecx
mov bl, 32
@@:
mov ecx, eax
shl eax, 5
add [esp+12], eax
xor eax, eax
push edi
repz scasd
jz @f
mov eax, [edi-4]
bsf eax, eax
xchg eax, ebx
test ecx, ecx
jnz @f
cmp ebx, eax
jc @f
mov ebx, eax
@@:
inc ecx
shl ecx, 5
sub ecx, ebx
sub [esp+16], ecx
mov ecx, edi
pop edi
sub ecx, edi
shr ecx, 2
dec ecx
or eax, -1
rep stosd
mov ecx, ebx
shl eax, cl
not eax
or [edi], eax
.done:
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jc .fail
mov eax, [esp]
call extfsReadDescriptor
jc .fail
mov ecx, [esp+8]
sub [eax+BGDESCR.blocksFree], cx
jc .fail
sub [ebp+EXTFS.superblock.blocksFree], ecx
mov eax, [esp]
call extfsWriteDescriptor
jc .fail
pop eax ebx
mul [ebp+EXTFS.superblock.blocksPerGroup]
mov ebx, eax
add ebx, esi
xor eax, eax
pop ecx
.ret:
pop edi esi edx
ret
.fail:
pop eax eax
movi eax, ERROR_DEVICE
xor ecx, ecx
jmp .ret
.next: ; search forward, then backward
pop eax
cmp eax, [esp]
jc .backward
inc eax
push eax
mul [ebp+EXTFS.superblock.blocksPerGroup]
cmp eax, [ebp+EXTFS.superblock.blocksTotal]
ja @f
mov eax, [esp]
jmp .test_block_group
@@:
pop eax eax
push eax
.backward:
dec eax
push eax
jns .test_block_group
pop eax eax
movi eax, ERROR_DISK_FULL
xor ecx, ecx
jmp .ret
extfsGetExtent:
; in: ecx = starting file block
; out: eax = first block number, ecx = extent size
push ebx edx esi
lea esi, [ebp+EXTFS.inodeBuffer]
test [esi+INODE.featureFlags], EXTENTS_USED
jz .listTreeSearch
add esi, INODE.blockNumbers
.extentTreeSearch:
cmp word [esi+NODEHEADER.magic], 0xF30A
jne .fail
movzx ebx, [esi+NODEHEADER.entriesFolow]
add esi, sizeof.NODEHEADER
test ebx, ebx
jz .noBlock
cmp word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0
je .leaf_block
dec ebx
jz .end_search_index
@@:
cmp ecx, [esi+sizeof.INDEX+INDEX.fileBlock]
jb .end_search_index
add esi, sizeof.INDEX
dec ebx
jnz @b
.end_search_index:
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov eax, [esi+INDEX.nodeBlock]
call extfsReadBlock
jc .fail2
mov esi, ebx
jmp .extentTreeSearch
.fail:
movi eax, ERROR_FS_FAIL
jmp .fail2
.leaf_block:
movzx edx, [esi+EXTENT.blocksCount]
add edx, [esi+EXTENT.fileBlock]
sub edx, ecx
ja .end_search_extent
add esi, sizeof.EXTENT
dec ebx
jnz .leaf_block
.noBlock:
movi eax, ERROR_END_OF_FILE
.fail2:
pop esi edx ebx
stc
ret
.end_search_extent:
sub ecx, [esi+EXTENT.fileBlock]
jc .fail
add ecx, [esi+EXTENT.fsBlock]
mov eax, ecx
mov ecx, edx
pop esi edx ebx
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]
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jz .noBlock
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 .noBlock
call extfsReadBlock
jc .fail2
mov eax, edx
jmp @f
.get_direct_block:
mov edx, ecx
mov cl, 12
lea ebx, [esi+INODE.blockNumbers]
jmp .calculateExtent
.get_indirect_block:
mov eax, [esi+INODE.addressBlock]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov edx, ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
jmp .calculateExtent
.get_double_indirect_block:
mov eax, [esi+INODE.doubleAddress]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov eax, ecx
@@:
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
; eax = number in doubly-indirect block, edx = number in indirect block
mov eax, [ebx+eax*4]
test eax, eax
jz .noBlock
call extfsReadBlock
jc .fail2
.calculateExtent:
lea esi, [ebx+edx*4]
lodsd
mov ebx, eax
sub ecx, edx
xor edx, edx
@@:
inc edx
dec ecx
jz @f
lodsd
sub eax, ebx
sub eax, edx
jz @b
@@:
mov eax, ebx
mov ecx, edx
pop esi edx ebx
clc
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
indirectBlockAlloc:
; in:
; edi -> indirect block number
; ebx = starting extent block
; ecx = extent size
; edx = starting file block
mov eax, [edi]
test eax, eax
jz .newBlock
push edi ebx ecx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .err2
lea edi, [ebx+edx*4]
test edx, edx
jz @f
cmp dword[edi-4], 0
jnz @f
pop ecx ebx edi
.err:
mov al, ERROR_FS_FAIL
stc
ret
.err2:
pop ecx ebx edi
ret
.newBlock:
test edx, edx
jnz .err
mov [edi], ebx
inc ebx
dec ecx
push edi ebx ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.tempBlockBuffer]
push edi
rep stosd
pop edi
@@:
mov ecx, [ebp+EXTFS.dwordsPerBlock]
sub ecx, edx
pop ebx eax
sub ebx, ecx
jnc @f
add ecx, ebx
xor ebx, ebx
@@:
jecxz .done
add edx, ecx
@@:
stosd
inc eax
loop @b
.done:
pop edi
push eax ebx
mov eax, [edi]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
pop ecx ebx
ret
doublyIndirectBlockAlloc:
; in:
; edi -> indirect block number
; edx = starting file block
; ebx = starting extent block
; ecx = extent size
; [esp+4] = rest of size
; [esp+8] = parent inode number
mov eax, [edi]
test eax, eax
jz .newBlock
push edi ecx ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .err2
mov eax, edx
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
lea edi, [ebx+eax*4]
pop ebx
test eax, eax
jz @f
cmp dword[edi-4], 0
jnz @f
pop ecx edi
.err:
mov al, ERROR_FS_FAIL
stc
ret
.err2:
pop ebx ecx edi
ret
.newBlock:
test edx, edx
jnz .err
mov [edi], ebx
inc ebx
dec ecx
inc dword[esp+4]
push edi ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.mainBlockBuffer]
push ecx edi
rep stosd
pop edi ecx
@@:
sub ecx, eax
xchg [esp], ecx
.loop:
cmp dword[edi], 0
jnz @f
inc dword[esp+12]
@@:
jecxz .extentAlloc
call indirectBlockAlloc
jc .end
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jnz @b
add edi, 4
xor edx, edx
dec dword[esp]
jnz .loop
.end:
pop edi edi
push ebx eax
mov eax, [edi]
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
pop ebx
add eax, ebx
xor ebx, ebx
cmp ebx, eax
pop ebx
ret
.extentAlloc:
mov ecx, [esp+12]
xor eax, eax
jecxz .end
mov eax, [esp+16]
call extfsExtentAlloc
jc .end
sub [esp+12], ecx
mov eax, ecx
imul eax, [ebp+EXTFS.sectorsPerBlock]
add [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
jmp @b
extfsExtendFile:
; in:
; [ebp+EXTFS.inodeBuffer] = inode
; eax = inode number
; ecx = new size
push ebx ecx edx esi edi eax
lea esi, [ebp+EXTFS.inodeBuffer]
mov eax, ecx
mov edx, [esi+INODE.fileSize]
cmp edx, eax
jnc .ret
mov [esi+INODE.fileSize], eax
mov ecx, [ebp+EXTFS.sectorsPerBlockLog]
add ecx, 9
dec eax
shr eax, cl
inc eax
sub edx, 1
jc @f
shr edx, cl
@@:
inc edx
sub eax, edx
jz .ret
push eax
@@:
mov ecx, [esp]
mov eax, [esp+4]
test ecx, ecx
jz .done
call extfsExtentAlloc
jc .errDone
sub [esp], ecx
mov eax, ecx
imul eax, [ebp+EXTFS.sectorsPerBlock]
add [esi+INODE.sectorsUsed], eax
cmp edx, 12
jc .directBlocks
sub edx, 12
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jc .indirectBlocks
sub edx, [ebp+EXTFS.dwordsPerBlock]
cmp edx, [ebp+EXTFS.dwordsPerBranch]
jc .doublyIndirectBlock
sub edx, [ebp+EXTFS.dwordsPerBranch]
jmp .triplyIndirectBlock
.newExtent:
jmp @b
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
test edx, edx
jz @f
cmp dword[edi-4], 0
jz .errDone
@@:
mov eax, ebx
mov ebx, ecx
mov ecx, 12
sub ecx, edx
sub ebx, ecx
jnc @f
add ecx, ebx
xor ebx, ebx
@@:
add edx, ecx
@@:
stosd
inc eax
loop @b
mov ecx, ebx
mov ebx, eax
jecxz .newExtent
xor edx, edx
.indirectBlocks:
lea edi, [esi+INODE.addressBlock]
cmp dword[edi], 0
jnz @f
inc dword[esp]
@@:
call indirectBlockAlloc
jc .errDone
add edx, 12
jecxz .newExtent
xor edx, edx
.doublyIndirectBlock:
lea edi, [esi+INODE.doubleAddress]
call doublyIndirectBlockAlloc
jc .errDone
mov edx, [ebp+EXTFS.dwordsPerBranch]
add edx, [ebp+EXTFS.dwordsPerBlock]
add edx, 12
jecxz .newExtent
xor edx, edx
.triplyIndirectBlock:
push ecx ebx edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
pop edx
mov esi, eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
test eax, eax
jz .newBlock
mov ebx, esi
call extfsReadBlock
pop ebx ecx
jc .errFree
mov eax, edx
xor edx, edx
div [ebp+EXTFS.dwordsPerBranch]
lea edi, [esi+eax*4]
test eax, eax
jz @f
cmp dword[edi-4], 0
jnz @f
mov al, ERROR_FS_FAIL
.errFree:
push ecx eax
stdcall kernel_free, esi
pop eax ecx
.errDone:
imul ecx, [ebp+EXTFS.sectorsPerBlock]
sub [ebp+EXTFS.inodeBuffer.sectorsUsed], ecx
pop ebx
imul ebx, [ebp+EXTFS.sectorsPerBlock]
add ebx, ecx
shl ebx, 9
sub [ebp+EXTFS.inodeBuffer.fileSize], ebx
stc
jmp .ret
.newBlock:
pop ebx ecx
mov al, ERROR_FS_FAIL
test edx, edx
jnz .errFree
mov [ebp+EXTFS.inodeBuffer.tripleAddress], ebx
inc ebx
dec ecx
inc dword[esp]
push ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, esi
xor eax, eax
rep stosd
mov edi, esi
pop ecx
@@:
jecxz .extentAlloc
call doublyIndirectBlockAlloc
jc .errSave
add edi, 4
jmp @b
.extentAlloc:
mov ecx, [esp]
mov eax, [esp+4]
jecxz @f
call extfsExtentAlloc
jc .errSave
sub [esp], ecx
mov eax, ecx
imul eax, [ebp+EXTFS.sectorsPerBlock]
add [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
jmp @b
@@:
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
stdcall kernel_free, esi
.done:
xor eax, eax
pop edi
.ret:
pop edi edi esi edx ecx ebx
ret
.errSave:
push eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
pop eax
jmp .errFree
freeIndirectBlock:
; in: edi -> indirect block number, edx = starting block
; out: edi = edi+4, eax=-1 -> done, eax=0 -> end
pushd ecx 0 edi edx
mov eax, [edi]
test eax, eax
jz .ret
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .ret
lea edi, [ebx+edx*4]
neg edx
add edx, [ebp+EXTFS.dwordsPerBlock]
xor ecx, ecx
@@:
mov eax, [edi]
test eax, eax
jz .end
call extfsResourceFree
stosd
dec edx
jnz @b
dec dword[esp+8]
.end:
pop edx edi
mov eax, [edi]
test edx, edx
jnz @f
call extfsResourceFree
stosd
jmp .done
@@:
call extfsWriteBlock
add edi, 4
.done:
pop eax ecx
xor edx, edx
ret
.ret:
pop edi edi edx ecx
ret
freeDoublyIndirectBlock:
; in: edi -> doubly-indirect block number, edx = starting block
; out: edi = edi+4, eax=-1 -> done, eax=0 -> end
mov eax, [edi]
test eax, eax
jz .ret
push ecx eax edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
mov ebx, eax
pop edx eax
pushd 0 ebx edx
call extfsReadBlock
jc .err
mov eax, edx
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
sub ecx, eax
push edi
lea edi, [ebx+eax*4]
@@:
call freeIndirectBlock
test eax, eax
jz .end
dec ecx
jnz @b
dec dword[esp+12]
.end:
pop edi edx
mov eax, [edi]
test edx, edx
jnz @f
xor ecx, ecx
call extfsResourceFree
stosd
jmp .done
@@:
mov ebx, [esp]
call extfsWriteBlock
add edi, 4
jmp .done
.err:
mov [esp+8], eax
pop eax
.done:
call kernel_free
pop eax ecx
.ret:
xor edx, edx
ret
extfsTruncateFile:
; in:
; [ebp+EXTFS.inodeBuffer] = inode
; ecx = new size
push ebx ecx edx esi edi
lea esi, [ebp+EXTFS.inodeBuffer]
cmp ecx, [esi+INODE.fileSize]
jnc .ret
mov [esi+INODE.fileSize], ecx
mov edx, ecx
jecxz .directBlocks
dec edx
mov ecx, [ebp+EXTFS.sectorsPerBlockLog]
add ecx, 9
shr edx, cl
inc edx
cmp edx, 12
jc .directBlocks
sub edx, 12
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jc .indirectBlocks
sub edx, [ebp+EXTFS.dwordsPerBlock]
cmp edx, [ebp+EXTFS.dwordsPerBranch]
jc .doublyIndirectBlock
sub edx, [ebp+EXTFS.dwordsPerBranch]
jmp .triplyIndirectBlock
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
neg edx
add edx, 12
xor ecx, ecx
@@:
mov eax, [edi]
test eax, eax
jz .ret
call extfsResourceFree
stosd
dec edx
jnz @b
.indirectBlocks:
lea edi, [esi+INODE.addressBlock]
call freeIndirectBlock
test eax, eax
jz .ret
.doublyIndirectBlock:
lea edi, [esi+INODE.doubleAddress]
call freeDoublyIndirectBlock
test eax, eax
jz .ret
.triplyIndirectBlock:
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jz .ret
push eax edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
mov ebx, eax
pop edx eax
push ebx eax edx
call extfsReadBlock
jc .err
mov eax, edx
xor edx, edx
div [ebp+EXTFS.dwordsPerBranch]
mov ecx, [ebp+EXTFS.dwordsPerBlock]
sub ecx, eax
lea edi, [ebx+eax*4]
@@:
call freeDoublyIndirectBlock
test eax, eax
jz .end
dec ecx
jnz @b
.end:
pop edx eax
test edx, edx
jnz @f
xor ecx, ecx
call extfsResourceFree
mov [esi+INODE.tripleAddress], eax
jmp .done
@@:
mov ebx, [esp]
call extfsWriteBlock
jmp .done
.err:
pop eax eax
.done:
call kernel_free
.ret:
pop 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.inodeBuffer]
mov ebx, esi
call readInode
jc .error_inode_read
mov ecx, [ebp+EXTFS.sectorsPerBlockLog]
add ecx, 9
mov eax, [esi+INODE.fileSize]
shr eax, cl
xor ecx, ecx
.searchBlock:
push eax ; blocks total
push ecx ; current file block number
cmp eax, ecx
jz .alloc_block
call extfsGetExtent
jc .error_get_inode_block
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error_block_read
mov ecx, [esp+12]
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
pop ecx ecx eax
inc ecx
jmp .searchBlock
.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
pop ecx
inc ecx
cmp ecx, [esp]
push ecx
jnz @f
.alloc_block:
mov ecx, [esi+INODE.fileSize]
add ecx, [ebp+EXTFS.bytesPerBlock]
mov eax, [esp+24]
call extfsExtendFile
jc .error_get_inode_block
mov eax, [esp+24]
mov ebx, esi
call writeInode
jc .error_get_inode_block
mov ecx, [esp]
@@:
call extfsGetExtent
jc .error_get_inode_block
push eax
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+DIRENTRY.entryLength], ax
.found:
pop edx ecx ecx ecx ebx esi
push ebx
mov [edi+DIRENTRY.inodeNumber], ebx
sub ecx, 8
mov word [edi+DIRENTRY.nameLength], cx
cmp [ebp+EXTFS.superblock.dynamicVersionFlag], 0
je .name
mov eax, [esp+4]
mov [edi+DIRENTRY.fileType], al
.name:
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.inodeBuffer]
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.inodeBuffer]
call readInode
jc .fail
push eax
.loop:
mov ecx, [esp]
call extfsGetExtent
jc .fail_loop
mov edi, eax
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.inodeBuffer]
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.inodeBuffer] = 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.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edx, esi
rep movsb
pop esi
pushd 0 ROOT_INODE
mov edi, esi
cmp [edx+INODE.sectorsUsed], 0
jz .not_found
cmp byte [esi], 0
jnz .next_path_part
xor eax, eax
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
call extfsGetExtent
jc @b
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.inodeBuffer]
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
jmp @f
.not_found:
mov esi, edi
call strlen
mov al, '/'
repnz scasb
mov edi, esi
jnz @f
xor edi, edi ; path folder 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.inodeBuffer]
test [esi+INODE.accessMode], FLAG_FILE
jnz .error_not_found
jmp @f
.root_folder:
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.inodeBuffer]
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 extfsGetExtent
jc .error_get_block
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 extfsGetExtent
jc .error_get_block
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 edi
pushd [edi+12]
mov edi, edx
xor eax, eax
mov ecx, 40 / 4
rep stosd
popd [edx+4] edi
mov eax, [ebx+DIRENTRY.inodeNumber]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
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
pushd 0 ERROR_ACCESS_DENIED
cmp byte [esi], 0
jz .ret ; root
mov [esp], ebx
call findInode
pop ebx
push eax
jc .ret
lea esi, [ebp+EXTFS.inodeBuffer]
mov byte [esp], ERROR_ACCESS_DENIED
test [esi+INODE.accessMode], FLAG_FILE
jz .ret ; not a file
mov byte [esp], ERROR_END_OF_FILE
mov eax, [esi+INODE.fileSize]
mov edx, [esi+INODE.fileSizeHigh]
sub eax, [ebx+4]
sbb edx, [ebx+8]
jc .ret
mov ecx, [ebx+12]
sub eax, ecx
sbb edx, 0
jc @f
xor eax, eax
mov [esp], eax
@@:
add ecx, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
mov edi, [ebx+16]
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .aligned
.piece:
push eax ecx
mov esi, edx
mov ecx, eax
call extfsGetExtent
jc .errorGet
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call fs_read64_sys
test eax, eax
jnz .errorRead
pop eax
mov ecx, [ebp+EXTFS.bytesPerBlock]
sub ecx, esi
sub eax, ecx
jnc @f
add ecx, eax
xor eax, eax
@@:
add esi, ebx
add [esp+8], ecx
rep movsb
mov ecx, eax
pop eax
inc eax
xor edx, edx
jecxz .ret
.aligned:
xchg eax, ecx
div [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, eax
.writeExtent:
test edx, edx
jz .end
push ecx
call extfsGetExtent
jc .errorGet
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
add [esp], ecx
imul ecx, [ebp+EXTFS.sectorsPerBlock]
mov ebx, edi
push edx ecx
mul [ebp+EXTFS.sectorsPerBlock]
call fs_read64_sys
pop ecx edx
test eax, eax
jnz .errorRead
shl ecx, 9
add edi, ecx
add [esp+12], ecx
pop ecx
jmp .writeExtent
.end:
mov eax, ecx
pop ecx
jecxz .ret
jmp .piece
.errorRead:
movi eax, ERROR_DEVICE
.errorGet:
pop ebx ebx
mov [esp], eax
.ret:
call ext_unlock
pop eax ebx
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.inodeBuffer]
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.inodeBuffer]
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.inodeBuffer]
movzx edx, [edx+INODE.accessMode]
and edx, TYPE_MASK
cmp edx, DIRECTORY
jne .file
push ebx ecx edx
xor ecx, ecx
.checkDirectory:
push ecx
call extfsGetExtent
jc .empty
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
pop ecx
inc ecx
jmp .checkDirectory
.empty:
cmp eax, ERROR_END_OF_FILE
jnz .not_empty_eax
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.inodeBuffer]
call readInode
jc .error_stack4_eax
xor ecx, ecx
call extfsTruncateFile ; free file's data
xor eax, eax
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
rep stosb
lea edi, [ebp+EXTFS.inodeBuffer]
push edx
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 eax
.error_stack8:
pop eax eax
push ERROR_ACCESS_DENIED
jmp .disk_sync
.not_empty_eax:
add esp, 12
.error_stack4_eax:
pop ebx
push eax
jmp .disk_sync
;----------------------------------------------------------------
ext_CreateFolder:
call extfsWritingInit
call findInode
jnc .success ; exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
inc ebx
push ebx esi edi
xor al, al
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
rep stosb
lea edi, [ebp+EXTFS.inodeBuffer]
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
pushd 0 0 ebx
call findInode
jnc .exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
inc ebx
push ebx ebx esi edi
xor al, al
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
rep stosb
lea edi, [ebp+EXTFS.inodeBuffer]
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
mov ecx, [ebx+12]
jmp ext_WriteFile.start
.exist:
movi eax, ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .error ; not a file
pop ebx
mov ecx, [ebx+12]
call extfsTruncateFile
jmp ext_WriteFile.start
.error2:
pop ebx
.error:
push eax
call ext_unlock
pop eax ebx ebx ebx
ret
;----------------------------------------------------------------
ext_WriteFile:
call extfsWritingInit
push ebx
call findInode
pop ebx
pushd 0 eax
jc .ret
mov byte [esp], ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .ret ; not a file
mov ecx, [ebx+4]
add ecx, [ebx+12]
.start:
push esi
mov eax, esi
call extfsExtendFile
jc .errorExtend
mov eax, [ebx+4]
mov ecx, [ebx+12]
mov esi, [ebx+16]
.write:
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .aligned
.piece:
mov ebx, ecx
mov edi, edx
mov ecx, eax
push eax
call extfsGetExtent
jc .errorGet
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
push ecx eax ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call fs_read64_sys
test eax, eax
jnz .errorDevice
pop eax
mov ecx, [ebp+EXTFS.bytesPerBlock]
sub ecx, edi
sub eax, ecx
jnc @f
add ecx, eax
xor eax, eax
@@:
add edi, ebx
add [esp+20], ecx
rep movsb
mov edi, eax
pop eax ecx
xor edx, edx
call fs_write64_sys
mov ecx, edi
pop eax
inc eax
xor edx, edx
jecxz .done
.aligned:
xchg eax, ecx
div [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, eax
.writeExtent:
test edx, edx
jz .end
push ecx
call extfsGetExtent
jc .errorGet2
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
add [esp], ecx
imul ecx, [ebp+EXTFS.sectorsPerBlock]
mov ebx, esi
push edx ecx
mul [ebp+EXTFS.sectorsPerBlock]
call fs_write64_sys
test eax, eax
jnz .errorDevice
pop ebx edx ecx
shl ebx, 9
add esi, ebx
add [esp+12], ebx
jmp .writeExtent
.end:
mov eax, ecx
pop ecx
jecxz .done
jmp .piece
.errorDevice:
pop eax eax
movi eax, ERROR_DEVICE
.errorGet2:
pop ebx
.errorGet:
pop ebx
.errorExtend:
mov [esp+4], eax
.done:
lea ebx, [ebp+EXTFS.inodeBuffer]
pop eax
call writeInode
add [esp], eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
pop eax ebx
ret
.erase:
push eax eax edx
mov eax, ebx
jmp .write
;----------------------------------------------------------------
ext_SetFileEnd:
call extfsWritingInit
pushd [ebx+4]
call findInode
pop ecx
jc .error2
lea edi, [ebp+EXTFS.inodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edi+INODE.accessMode], FLAG_FILE
jz .error2 ; not a file
push esi
mov ebx, [edi+INODE.fileSize]
mov eax, esi
cmp ebx, ecx
jnc @f
call extfsExtendFile
jc .error
sub ecx, ebx
cmp ecx, 1000001h
jnc .done
push ecx
stdcall kernel_alloc, ecx
pop ecx
test eax, eax
jz .error
push ecx
add ecx, 3
shr ecx, 2
mov esi, eax
mov edi, eax
xor eax, eax
rep stosd
pop ecx edx
push esi
call ext_WriteFile.erase
call kernel_free
xor eax, eax
ret
@@:
call extfsTruncateFile
.done:
xor eax, eax
.error:
xchg eax, [esp]
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
add [esp], eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
pop eax
.error2:
push eax
call ext_unlock
pop eax
ret