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