forked from KolibriOS/kolibrios
Magomed Kostoev (mkostoevr)
360e379fc7
git-svn-id: svn://kolibrios.org@9047 a494cfbc-eb01-0410-851d-a64ba20cac60
2709 lines
70 KiB
PHP
2709 lines
70 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
|
|
dd ext_Rename
|
|
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 ?
|
|
UUID rb 16
|
|
volumeLabel rb 16
|
|
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
|
|
@@:
|
|
add edi, 8
|
|
rep movsb
|
|
mov eax, edx
|
|
mov ebx, [ebp+EXTFS.tempBlockBuffer]
|
|
call extfsWriteBlock
|
|
@@:
|
|
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 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:
|
|
xor ebx, ebx
|
|
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:
|
|
cmp byte [esi], 0
|
|
jz .volume
|
|
call ext_lock
|
|
call findInode
|
|
jc .ret
|
|
lea esi, [ebp+EXTFS.inodeBuffer]
|
|
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
|
|
xor eax, eax
|
|
.ret:
|
|
push eax
|
|
call ext_unlock
|
|
pop eax
|
|
@@:
|
|
ret
|
|
|
|
.volume:
|
|
mov eax, dword[ebp+EXTFS.Length]
|
|
mov edx, dword[ebp+EXTFS.Length+4]
|
|
mov edi, [ebx+16]
|
|
shld edx, eax, 9
|
|
shl eax, 9
|
|
mov [edi+36], edx
|
|
mov [edi+32], eax
|
|
mov eax, [ebx+8]
|
|
mov byte [edi], 8
|
|
mov [edi+4], eax
|
|
test eax, eax
|
|
jz @b
|
|
lea esi, [ebp+EXTFS.superblock.volumeLabel]
|
|
mov ecx, 16
|
|
add edi, 40
|
|
cmp eax, 3
|
|
jz .utf8
|
|
add ecx, esi
|
|
cmp eax, 2
|
|
jz .utf16
|
|
@@:
|
|
call utf8to16
|
|
call uni2ansi_char
|
|
stosb
|
|
cmp esi, ecx
|
|
jc @b
|
|
jmp @f
|
|
|
|
.utf8:
|
|
rep movsb
|
|
jmp @f
|
|
|
|
.utf16:
|
|
call utf8to16
|
|
stosw
|
|
cmp esi, ecx
|
|
jc .utf16
|
|
@@:
|
|
xor eax, eax
|
|
mov [edi], ax
|
|
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 byte [ebx+INODE.linksCount], 2
|
|
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
|
|
push esi
|
|
mov eax, esi
|
|
mov ebx, edx
|
|
mov esi, edi
|
|
mov dl, DIR_DIRECTORY
|
|
call linkInode
|
|
pop edx
|
|
jc .error
|
|
push ebx
|
|
lea ebx, [ebp+EXTFS.inodeBuffer]
|
|
inc [ebx+INODE.linksCount]
|
|
mov eax, edx
|
|
call writeInode
|
|
pop ebx
|
|
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 byte [ebx+INODE.linksCount], 1
|
|
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
|
|
mov eax, ebx
|
|
lea ebx, [ebp+EXTFS.inodeBuffer]
|
|
call readInode
|
|
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
|
|
|
|
;----------------------------------------------------------------
|
|
ext_Rename:
|
|
call extfsWritingInit
|
|
push esi
|
|
mov esi, edi
|
|
call findInode
|
|
jnc .error
|
|
test edi, edi
|
|
jz .error
|
|
xchg [esp], esi
|
|
push edi
|
|
call findInode
|
|
pop edi
|
|
jc .error
|
|
xor edx, edx
|
|
inc edx
|
|
test [ebp+EXTFS.inodeBuffer.accessMode], DIRECTORY
|
|
jz @f
|
|
inc edx
|
|
@@:
|
|
mov eax, ecx
|
|
push ecx edx
|
|
call unlinkInode
|
|
pop edx ecx
|
|
jc .error
|
|
cmp edx, 1
|
|
jz @f
|
|
lea ebx, [ebp+EXTFS.inodeBuffer]
|
|
dec [ebx+INODE.linksCount]
|
|
mov eax, ecx
|
|
call writeInode
|
|
jc .error
|
|
@@:
|
|
mov ebx, esi
|
|
mov esi, edi
|
|
pop eax
|
|
push eax edx
|
|
call linkInode
|
|
pop edx
|
|
jc .error
|
|
pop eax
|
|
cmp edx, 1
|
|
jz @f
|
|
lea ebx, [ebp+EXTFS.inodeBuffer]
|
|
inc [ebx+INODE.linksCount]
|
|
call writeInode
|
|
@@:
|
|
call writeSuperblock
|
|
mov esi, [ebp+PARTITION.Disk]
|
|
call disk_sync
|
|
call ext_unlock
|
|
xor eax, eax
|
|
ret
|
|
|
|
.error:
|
|
push eax
|
|
call ext_unlock
|
|
pop eax ebx
|
|
ret
|