kolibrios/kernel/trunk/fs/ext.inc

2680 lines
69 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 ?
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
extfsGetFileBlock:
; in: esi -> inode, ecx = file block number
; 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:
mov eax, [esi+INODE.addressBlock]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
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
push edx ebx
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
.noBlock:
xor ecx, ecx
.fail2:
pop ebx edx
ret
.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
div [ebp+EXTFS.dwordsPerBlock]
; 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
mov ecx, [ebx+edx*4]
pop ebx edx
ret
extfsReadFileBlock:
; in:
; eax = file block number
; [ebp+EXTFS.inodeBuffer] = inode
; out:
; [ebp+EXTFS.mainBlockBuffer] -> block
push ebx ecx edx esi
mov ecx, eax
lea esi, [ebp+EXTFS.inodeBuffer]
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
; ebx -> data
; [ebp+EXTFS.inodeBuffer] = inode
push ecx edx esi
mov ecx, eax
lea esi, [ebp+EXTFS.inodeBuffer]
call extfsGetFileBlock
jc @f
test ecx, ecx
jz @b
mov eax, ecx
call extfsWriteBlock
@@:
pop esi edx ecx
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 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+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
.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
jmp @f
.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
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
lea esi, [ebp+EXTFS.inodeBuffer]
.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.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
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.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 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 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
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.inodeBuffer]
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.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 0
lea esi, [ebp+EXTFS.inodeBuffer]
.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.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
push 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
push ebx esi
mov ecx, [ebx+12]
jmp ext_WriteFile.start
.exist:
lea edx, [ebp+EXTFS.inodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edx+INODE.accessMode], FLAG_FILE
jz .error ; not a file
pop ebx
push ebx esi
mov ecx, [ebx+12]
call extfsTruncateFile
jmp 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.inodeBuffer]
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
mov ecx, [ebx+12]
push eax
jc .error_inode_size
pop eax
mov eax, [ebx+4]
mov ebx, [ebx+16]
push 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
@@:
mov edi, eax
call extfsReadFileBlock
jc .error_inode_size
mov eax, edi
push ebx ecx
mov ecx, esi
mov edi, [ebp+EXTFS.mainBlockBuffer]
mov esi, ebx
mov ebx, edi
add edi, edx
mov edx, ecx
rep movsb
call extfsWriteFileBlock
pop ecx ebx
jc .error_inode_size
add [esp], edx
add ebx, edx
sub ecx, edx
jz .write_inode
.start_aligned:
cmp ecx, [ebp+EXTFS.bytesPerBlock]
jb @f
mov eax, [esp]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
call extfsWriteFileBlock
jc .error_inode_size
mov eax, [ebp+EXTFS.bytesPerBlock]
sub ecx, eax
add ebx, 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 ecx
mov esi, ebx
mov edi, [ebp+EXTFS.mainBlockBuffer]
mov ebx, edi
rep movsb
pop ecx
call extfsWriteFileBlock
jc .error_inode_size
xor ecx, ecx
.error_inode_size:
mov [esp+12], eax
.write_inode:
lea ebx, [ebp+EXTFS.inodeBuffer]
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
jc .error2
lea edi, [ebp+EXTFS.inodeBuffer]
movi eax, ERROR_ACCESS_DENIED
cmp [edi+INODE.accessMode], FLAG_FILE
jnz .error2 ; not a file
pop ecx
push esi
mov ebx, [edi+INODE.fileSize]
mov eax, esi
cmp ebx, ecx
jc @f
call extfsTruncateFile
jmp .done
@@:
call extfsExtendFile
jc .error
sub ecx, ebx
mov eax, ebx
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
mov edi, eax
test edx, edx
jz .start_aligned
call extfsReadFileBlock
jc .error
mov eax, [ebp+EXTFS.bytesPerBlock]
sub eax, edx
cmp eax, ecx
jbe @f
mov eax, ecx
@@:
mov ebx, [ebp+EXTFS.mainBlockBuffer]
push edi ecx
mov ecx, eax
mov edi, ebx
add edi, edx
xor eax, eax
mov edx, ecx
rep stosb
pop ecx edi
mov eax, edi
call extfsWriteFileBlock
jc .error
sub ecx, edx
jz .done
inc edi
.start_aligned:
mov eax, ecx
mov ecx, [ebp+EXTFS.bytesPerBlock]
dec eax
xor edx, edx
div ecx
inc eax
mov ebx, [ebp+EXTFS.mainBlockBuffer]
push eax edi
mov edi, ebx
xor eax, eax
rep stosb
pop edi ecx
@@:
mov eax, edi
call extfsWriteFileBlock
jc .error
inc edi
loop @b
.done:
xor eax, eax
.error:
xchg eax, [esp]
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
jnc @f
mov [esp], eax
@@:
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
mov eax, [esp]
.error2:
mov [esp], eax
call ext_unlock
pop eax
ret