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

2605 lines
67 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
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 ?
bytesPerBlock dd ?
sectorsPerBlock dd ?
dwordsPerBlock dd ?
dwordsPerBranch dd ? ; dwordsPerBlock ^ 2
mainBlockBuffer dd ?
tempBlockBuffer dd ?
descriptorTable dd ?
descriptorTableEnd 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], 512
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 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
@@:
mov eax, [ebx+SUPERBLOCK.inodesTotal]
dec eax
xor edx, edx
div [ebx+SUPERBLOCK.inodesPerGroup]
inc eax
shl eax, 5
push eax eax
call kernel_alloc
pop ecx
test eax, eax
jz .error2
mov [ebp+EXTFS.descriptorTable], eax
mov ebx, eax
add eax, ecx
mov [ebp+EXTFS.descriptorTableEnd], eax
mov eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mul [ebp+EXTFS.sectorsPerBlock]
dec ecx
shr ecx, 9
inc ecx
call fs_read64_sys
test eax, eax
jnz @f
mov al, ROOT_INODE
lea ebx, [ebp+EXTFS.rootInodeBuffer]
call readInode
test eax, eax
jnz @f
mov eax, ebp
pop edi esi ebp ebx
ret
@@:
stdcall kernel_free, [ebp+EXTFS.descriptorTable]
.error2:
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 [eax+EXTFS.mainBlockBuffer]
stdcall kernel_free, [eax+EXTFS.descriptorTable]
call kernel_free
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
extfsWriteDescriptor:
; in: ebx = block group descriptor
mov eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mul [ebp+EXTFS.sectorsPerBlock]
sub ebx, [ebp+EXTFS.descriptorTable]
shr ebx, 9
add eax, ebx
shl ebx, 9
add ebx, [ebp+EXTFS.descriptorTable]
call fs_write32_sys
ret
extfsExtentFree:
; in: eax = first block number, ecx = extent size
push ebx edx edi
sub eax, [ebp+EXTFS.superblock.firstGroupBlock]
xor edx, edx
mov ebx, [ebp+EXTFS.superblock.blocksPerGroup]
div ebx
sub ebx, edx
sub ebx, ecx
jc .ret
push edx
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
mov eax, ecx
mul [ebp+EXTFS.sectorsPerBlock]
add [ebx+BGDESCR.blocksFree], cx
add [ebp+EXTFS.superblock.blocksFree], ecx
sub [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
push [ebx+BGDESCR.blockBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
call extfsReadBlock
pop eax
jc .ret
push ebx edx
mov edi, eax
shr edi, 5
shl edi, 2
add edi, ebx
mov edx, ecx
and eax, 31
jz .aligned
mov ecx, 32
sub ecx, eax
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
or ebx, -1
shl ebx, cl
not ebx
mov ecx, eax
shl ebx, cl
not ebx
and [edi], ebx
add edi, 4
xor eax, eax
.aligned:
mov ecx, edx
shr ecx, 5
rep stosd
and edx, 31
jz @f
mov ecx, edx
not eax
shl eax, cl
and [edi], eax
@@:
pop eax ebx
call extfsWriteBlock
.ret:
pop edi edx ebx
xor eax, eax
ret
extfsInodeAlloc:
; in: eax = parent inode number
; out: ebx = allocated inode number
push ecx edx edi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
push ebx
.test_block_group:
push ebx
cmp [ebx+BGDESCR.blocksFree], 0
jz .next
cmp [ebx+BGDESCR.inodesFree], 0
jz .next
dec [ebx+BGDESCR.inodesFree]
dec [ebp+EXTFS.superblock.inodesFree]
push [ebx+BGDESCR.inodeBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
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
pop eax
sub eax, [ebp+EXTFS.descriptorTable]
shr eax, 5
mul [ebp+EXTFS.superblock.inodesPerGroup]
lea ebx, [eax+ecx+1]
xor eax, eax
.ret:
pop edi edi edx ecx
ret
.next: ; search forward, then backward
pop ebx
cmp ebx, [esp]
jc .backward
add ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTableEnd]
jc .test_block_group
mov ebx, [esp]
.backward:
sub ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTable]
jnc .test_block_group
movi eax, ERROR_DISK_FULL
push eax
.fail:
pop edi
jmp .ret
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]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
push ebx
.test_block_group:
push ebx
cmp [ebx+BGDESCR.blocksFree], 0
jz .next
mov eax, [ebx+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
@@:
or eax, -1
cmp ebx, 32
jz @f
xchg ebx, ecx
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
jecxz .done
neg ecx
add ecx, 32
shr eax, cl
or [edi], eax
.done:
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
mov ebx, [esp]
mov ecx, [esp+8]
sub [ebx+BGDESCR.blocksFree], cx
jnc @f
mov [ebx+BGDESCR.blocksFree], 0
@@:
sub [ebp+EXTFS.superblock.blocksFree], ecx
call extfsWriteDescriptor
pop eax ebx
sub eax, [ebp+EXTFS.descriptorTable]
shr eax, 5
mul [ebp+EXTFS.superblock.blocksPerGroup]
mov ebx, eax
add ebx, esi
add ebx, [ebp+EXTFS.superblock.firstGroupBlock]
pop ecx
mov eax, ecx
mul [ebp+EXTFS.sectorsPerBlock]
add [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
xor eax, eax
.ret:
pop edi esi edx
ret
.next: ; search forward, then backward
pop ebx
cmp ebx, [esp]
jc .backward
add ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTableEnd]
jc .test_block_group
mov ebx, [esp]
.backward:
sub ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTable]
jnc .test_block_group
movi eax, ERROR_DISK_FULL
push eax
.fail:
add esp, 12
xor ecx, ecx
stc
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
test eax, eax
jz .noBlock
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: eax = inode sector, edx = offset in sector
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
shl eax, 5
add eax, [ebp+EXTFS.descriptorTable]
mov ebx, [eax+BGDESCR.inodeTable]
imul ebx, [ebp+EXTFS.sectorsPerBlock]
movzx eax, [ebp+EXTFS.superblock.inodeSize]
mul edx
mov edx, eax
shr eax, 9
and edx, 511
add eax, ebx
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
cmp eax, ROOT_INODE
jnz @f
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov esi, edi
lea edi, [ebp+EXTFS.rootInodeBuffer]
rep movsb
@@:
call getInodeLocation
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call fs_read32_sys
test eax, eax
jnz @f
mov eax, ecx
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edi, edx
add edi, ebx
mov esi, [esp]
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
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
jmp @b
extfsExtendFile:
; in:
; [ebp+EXTFS.inodeBuffer] = inode
; ecx = inode number
; edx:eax = new size
push ebx esi edi ecx
lea esi, [ebp+EXTFS.inodeBuffer]
mov ebx, [esi+INODE.fileSize]
mov ecx, [esi+INODE.fileSizeHigh]
cmp ebx, eax
sbb ecx, edx
jnc .ret
mov ecx, [esi+INODE.fileSizeHigh]
mov [esi+INODE.fileSize], eax
mov [esi+INODE.fileSizeHigh], edx
sub eax, 1
sbb edx, 0
div [ebp+EXTFS.bytesPerBlock]
inc eax
xchg eax, ebx
mov edx, ecx
sub eax, 1
sbb edx, 0
jc @f
div [ebp+EXTFS.bytesPerBlock]
@@:
inc eax
sub ebx, eax
jz .ret
push ebx
mov edx, eax
@@:
mov ecx, [esp]
mov eax, [esp+4]
test ecx, ecx
jz .done
call extfsExtentAlloc
jc .errDone
sub [esp], ecx
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
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 ebx
ret
.errSave:
push eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
pop eax
jmp .errFree
freeBlockList:
; in: edi -> list of blocks, edx = amount of blocks
; out: ebx=0 -> end of list
mov ebx, [edi]
test ebx, ebx
jz .ret
xor eax, eax
xor ecx, ecx
@@:
stosd
inc ecx
dec edx
jz @f
mov eax, [edi]
sub eax, ebx
sub eax, ecx
jz @b
@@:
mov eax, ebx
call extfsExtentFree
test edx, edx
jnz freeBlockList
.ret:
ret
freeIndirectBlock:
; in: edi -> indirect block number, edx = starting block
; out: edi = edi+4, 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]
call freeBlockList
test ebx, ebx
jz @f
inc dword[esp+8]
@@:
pop edx edi
mov eax, [edi]
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
stosd
jmp .done
@@:
mov ebx, [ebp+EXTFS.mainBlockBuffer]
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
inc ecx
call extfsExtentFree
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: edx:eax = new size, [ebp+EXTFS.inodeBuffer] = inode
lea esi, [ebp+EXTFS.inodeBuffer]
mov ecx, edx
cmp eax, [esi+INODE.fileSize]
sbb ecx, [esi+INODE.fileSizeHigh]
jnc .ret
mov [esi+INODE.fileSize], eax
mov [esi+INODE.fileSizeHigh], edx
sub eax, 1
sbb edx, 0
jc @f
div [ebp+EXTFS.bytesPerBlock]
@@:
inc eax
mov edx, 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
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
neg edx
add edx, 12
call freeBlockList
test ebx, ebx
jz .ret
.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
inc ecx
call extfsExtentFree
mov [esi+INODE.tripleAddress], eax
jmp .done
@@:
mov ebx, [esp]
call extfsWriteBlock
jmp .done
.err:
pop eax eax
.done:
call kernel_free
.ret:
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
push esi ebx ecx
lea esi, [ebp+EXTFS.inodeBuffer]
mov ebx, esi
call readInode
jc .error_inode_read
mov eax, [esi+INODE.fileSize]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
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]
add ecx, 8 ; directory entry size
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
@@:
pop ecx eax
inc ecx
jmp .searchBlock
.zeroLength:
mov eax, edx
sub eax, edi
mov [edi+DIRENTRY.entryLength], ax
cmp eax, ecx
jge .found
mov [edi+DIRENTRY.inodeNumber], 0
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jmp @b
.alloc_block:
mov eax, [esi+INODE.fileSize]
add eax, [ebp+EXTFS.bytesPerBlock]
xor edx, edx
mov ecx, [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
mov [edi+DIRENTRY.inodeNumber], ebx
mov word [edi+DIRENTRY.nameLength], cx
sub eax, 8
cmp ecx, eax
adc ecx, 0
test [ebp+EXTFS.superblock.incompatibleFlags], 2
jz @f
mov eax, [esp]
mov [edi+DIRENTRY.fileType], al
@@:
push ebx
add edi, 8
rep movsb
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
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 = directory inode number, esi = inode to unlink
push edi
lea ebx, [ebp+EXTFS.inodeBuffer]
call readInode
jc .ret
xor ecx, ecx
.loop:
push ecx
call extfsGetExtent
jc .fail_loop
mov edi, eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_loop
.first_dir_entry: ; edi -> block
cmp [ebx+DIRENTRY.inodeNumber], esi
jne @f
mov [ebx+DIRENTRY.inodeNumber], 0
mov word [ebx+DIRENTRY.nameLength], 0 ; fileType = 0
jmp .write_block
.fail:
pop edi
movi eax, ERROR_FS_FAIL
stc
.fail_loop:
pop edi
jmp .ret
.next:
pop ecx ecx
inc ecx
jmp .loop
@@:
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
push edx
@@:
movzx ecx, [ebx+DIRENTRY.entryLength]
jecxz .fail
mov edx, ebx
add ebx, ecx
cmp ebx, [esp]
jnc .next
cmp [ebx+DIRENTRY.inodeNumber], esi
jnz @b
mov cx, [ebx+DIRENTRY.entryLength]
add [edx+DIRENTRY.entryLength], cx
pop eax
.write_block:
pop eax
mov eax, edi
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
.ret:
pop edi
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 ebx 0 ROOT_INODE
mov edi, esi
cmp [edx+INODE.fileSize], 0
jz .not_found
cmp byte [esi], 0
jnz .next_path_part
xor eax, eax
pop esi ecx ebx
ret
@@:
pop esi esi
.error:
pop esi ecx ebx
xor edi, edi
stc
ret
.next_path_part:
push [edx+INODE.fileSize]
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 ecx, [ebx+DIRENTRY.entryLength]
jecxz .stop
add ebx, ecx
cmp ebx, edx
jb .start_rec
jmp .stop
.test_find:
cmp byte [esi], 0
je @f
cmp byte [esi], '/'
jne @b
inc esi
@@:
pop edx
.stop:
pop edx edi ecx eax
; ebx -> matched directory entry, esi -> name without parent, or not changed
cmp edi, esi
jnz @f
sub eax, [ebp+EXTFS.bytesPerBlock]
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 ebx
ret
writeSuperblock:
push ebx
mov eax, 2
lea ebx, [ebp+EXTFS.superblock]
call fs_write32_sys
pop ebx
ret
extfsWritingInit:
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
call findInode
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]
cmp byte [esi], '.'
jnz @f
or byte [edx], KOS_HIDDEN
@@:
lea edi, [edx+40]
cmp byte [edx+4], 3
jz .utf8
add ecx, esi
cmp byte [edx+4], 2
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
.utf8:
rep movsb
mov byte [edi], 0
add edx, 40+520
jmp @b
.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
call findInode
pushd 0 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
cmp byte [esi], 0
jz .is_root
call findInode
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 edx, [ebx+16]
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
call findInode
jc @f
push esi
mov esi, [ebx+16]
add esi, 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
jc .error
push ecx
movzx edi, [ebp+EXTFS.inodeBuffer.accessMode]
and edi, TYPE_MASK
cmp edi, DIRECTORY
jne .file
xor ecx, ecx
.checkDirectory:
push ecx
call extfsGetExtent
jc .empty
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error8
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
.dir_entry:
movzx ecx, [ebx+DIRENTRY.nameLength]
mov ax, word [ebx+DIRENTRY.name]
jecxz @f
cmp al, '.'
jnz .not_empty
dec ecx
jz @f
cmp al, ah
jnz .not_empty
dec ecx
jnz .not_empty
@@:
mov cx, [ebx+DIRENTRY.entryLength]
jecxz @f
add ebx, ecx
cmp ebx, edx
jb .dir_entry
@@:
pop ecx
inc ecx
jmp .checkDirectory
.not_empty:
pop eax eax
push ERROR_ACCESS_DENIED
jmp .ret
.error8:
pop ebx
.error4:
pop ebx
.error:
push eax
jmp .ret
.empty:
pop ecx ecx
cmp eax, ERROR_END_OF_FILE
jnz .error
push ecx
.file:
mov eax, ecx
call unlinkInode
jc .error4
pop eax
lea ebx, [ebp+EXTFS.inodeBuffer]
cmp edi, DIRECTORY
jnz @f
dec [ebx+INODE.linksCount]
call writeInode
@@:
mov eax, esi
call readInode
jc .error
dec [ebx+INODE.linksCount]
jz @f
cmp edi, DIRECTORY
jnz .hardlinks
@@:
push esi edi
xor eax, eax
xor edx, edx
call extfsTruncateFile ; free file's data
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
lea edi, [ebp+EXTFS.inodeBuffer]
xor eax, eax
push edi
rep stosb
call fsGetTime
pop ebx edi esi
add eax, 978307200
mov [ebx+INODE.deletedTime], eax
mov eax, esi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
push edx
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
cmp edi, DIRECTORY
jnz @f
dec [ebx+BGDESCR.directoriesCount]
@@:
inc [ebx+BGDESCR.inodesFree]
push [ebx+BGDESCR.inodeBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call extfsReadBlock
pop edx
jc .error
mov eax, edx
and edx, 31
shr eax, 5
shl eax, 2
add eax, ebx
btr [eax], edx
mov eax, ecx
call extfsWriteBlock
inc [ebp+EXTFS.superblock.inodesFree]
.hardlinks:
mov eax, esi
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
xor ebx, ebx
pop eax
ret
;----------------------------------------------------------------
ext_CreateFolder:
call extfsWritingInit
call findInode
jnc .success ; exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
push ebx esi edi
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
xor eax, eax
rep stosb
call fsGetTime
add eax, 978307200
lea ebx, [ebp+EXTFS.inodeBuffer]
mov [ebx+INODE.accessedTime], eax
mov [ebx+INODE.dataModified], eax
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], DIRECTORY or 511
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 ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
inc [ebx+BGDESCR.directoriesCount]
call extfsWriteDescriptor
.success:
.error:
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
pop eax
ret
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
push ebx ebx esi edi
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
xor eax, eax
rep stosb
call fsGetTime
add eax, 978307200
lea ebx, [ebp+EXTFS.inodeBuffer]
mov [ebx+INODE.accessedTime], eax
mov [ebx+INODE.dataModified], eax
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], FLAG_FILE or 110110110b
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 eax, [ebx+12]
xor edx, edx
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 eax, [ebx+12]
xor edx, edx
push eax edx ebx esi
call extfsTruncateFile
pop esi ebx edx eax
jmp ext_WriteFile.start
.error2:
pop ebx
.error:
push eax
call ext_unlock
pop eax ebx ebx ebx
ret
;----------------------------------------------------------------
ext_WriteFile:
call extfsWritingInit
call findInode
pushd 0 eax
jc .ret
mov byte [esp], ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .ret ; not a file
mov byte [esp], 0
mov eax, [ebx+4]
mov edx, [ebx+8]
add eax, [ebx+12]
adc edx, 0
.start:
push esi
mov ecx, esi
call extfsExtendFile
jc .errorExtend
mov eax, [ebx+4]
mov edx, [ebx+8]
mov ecx, [ebx+12]
mov esi, [ebx+16]
.write:
jecxz .zero
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
.zero:
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 edi
mov eax, ebx
jmp .write
;----------------------------------------------------------------
ext_SetFileEnd:
call extfsWritingInit
call findInode
jc .error2
lea edi, [ebp+EXTFS.inodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edi+INODE.accessMode], FLAG_FILE
jz .error2 ; not a file
mov eax, [ebx+4]
mov edx, [ebx+8]
mov ebx, [edi+INODE.fileSize]
mov ecx, [edi+INODE.fileSizeHigh]
push esi ecx
cmp ebx, eax
sbb ecx, edx
mov ecx, esi
jnc @f
call extfsExtendFile
pop esi
jc .error
mov eax, [edi+INODE.fileSize]
mov edx, [edi+INODE.fileSizeHigh]
sub eax, ebx
sbb edx, esi
jnz .done
cmp eax, 1000001h
jnc .done
push eax
stdcall kernel_alloc, eax
pop ecx
test eax, eax
jz .error
push ecx
add ecx, 3
shr ecx, 2
mov edx, esi
mov esi, eax
mov edi, eax
xor eax, eax
rep stosd
pop ecx edi
push esi
call ext_WriteFile.erase
call kernel_free
xor eax, eax
ret
@@:
call extfsTruncateFile
pop eax
.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