da8c332884
git-svn-id: svn://kolibrios.org@4850 a494cfbc-eb01-0410-851d-a64ba20cac60
1854 lines
50 KiB
PHP
1854 lines
50 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; ;;
|
||
;; Contains ext2 inode handling code. ;;
|
||
;; ;;
|
||
;; Copyright (C) KolibriOS team 2013-2014. All rights reserved. ;;
|
||
;; Distributed under the terms of the new BSD license. ;;
|
||
;; ;;
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
||
$Revision$
|
||
|
||
|
||
;---------------------------------------------------------------------
|
||
; Receives block number from extent-based inode.
|
||
; Input: ecx = number of block in inode
|
||
; esi = address of extent header
|
||
; ebp = pointer to EXTFS
|
||
; Output: ecx = address of next block, if successful
|
||
; eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext4_block_recursive_search:
|
||
cmp word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC
|
||
jne .fail
|
||
|
||
movzx ebx, [esi + EXT4_EXTENT_HEADER.eh_entries]
|
||
add esi, sizeof.EXT4_EXTENT_HEADER
|
||
cmp word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0
|
||
je .leaf_block ;листовой ли это блок?
|
||
|
||
;не листовой блок, а индексный ; eax - ext4_extent_idx
|
||
test ebx, ebx
|
||
jz .fail ;пустой индексный блок -> ошибка
|
||
|
||
;цикл по индексам экстентов
|
||
@@:
|
||
cmp ebx, 1 ;у индексов не хранится длина,
|
||
je .end_search_index ;поэтому, если остался последний - то это нужный
|
||
|
||
cmp ecx, [esi + EXT4_EXTENT_IDX.ei_block]
|
||
jb .fail
|
||
|
||
cmp ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса
|
||
jb .end_search_index ;следующий дальше - значит текущий, то что нам нужен
|
||
|
||
add esi, sizeof.EXT4_EXTENT_IDX
|
||
dec ebx
|
||
jmp @B
|
||
|
||
.end_search_index:
|
||
;ebp указывает на нужный extent_idx, считываем следующий блок
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
mov eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail
|
||
mov esi, ebx
|
||
jmp ext4_block_recursive_search ;рекурсивно прыгаем в начало
|
||
|
||
.leaf_block: ;листовой блок esi - ext4_extent
|
||
;цикл по экстентам
|
||
@@:
|
||
test ebx, ebx
|
||
jz .fail ;ни один узел не подошел - ошибка
|
||
|
||
mov edx, [esi + EXT4_EXTENT.ee_block]
|
||
cmp ecx, edx
|
||
jb .fail ;если меньше, значит он был в предыдущих блоках -> ошибка
|
||
|
||
movzx edi, [esi + EXT4_EXTENT.ee_len]
|
||
add edx, edi
|
||
cmp ecx, edx
|
||
jb .end_search_extent ;нашли нужный блок
|
||
|
||
add esi, sizeof.EXT4_EXTENT
|
||
dec ebx
|
||
jmp @B
|
||
|
||
.end_search_extent:
|
||
mov edx, [esi + EXT4_EXTENT.ee_start_lo]
|
||
sub ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках
|
||
add ecx, edx
|
||
xor eax, eax
|
||
ret
|
||
|
||
.fail:
|
||
mov eax, ERROR_FS_FAIL
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Frees triply indirect block.
|
||
; Input: eax = triply indirect block.
|
||
; [ebp + EXTFS.ext2_save_inode] = the inode.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_free_triply_indirect:
|
||
push ebx edx
|
||
|
||
test eax, eax
|
||
jz .success
|
||
push eax
|
||
; Read the triple indirect block.
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
pop eax
|
||
jnz .fail
|
||
|
||
; Free the triple indirect block.
|
||
call ext2_block_free
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov edx, ebx
|
||
add edx, [ebp + EXTFS.block_size]
|
||
|
||
@@:
|
||
mov eax, [ebx]
|
||
test eax, eax
|
||
jz .success
|
||
|
||
call ext2_inode_free_doubly_indirect
|
||
cmp eax, 1
|
||
je .success
|
||
cmp eax, 0xFFFFFFFF
|
||
je .fail
|
||
|
||
add ebx, 4
|
||
cmp ebx, edx
|
||
jb @B
|
||
|
||
.success:
|
||
xor eax, eax
|
||
.ret:
|
||
pop edx ebx
|
||
ret
|
||
|
||
.fail:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Frees double indirect block.
|
||
; Input: eax = double indirect block.
|
||
; [ebp + EXTFS.ext2_save_inode] = the inode.
|
||
; Output: eax = error code, 1 implies finished, ~0 implies error
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_free_doubly_indirect:
|
||
push ebx edx
|
||
|
||
test eax, eax
|
||
jz .complete
|
||
push eax
|
||
; Read the double indirect block.
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
pop eax
|
||
jnz .fail
|
||
|
||
call ext2_block_free
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov edx, ebx
|
||
add edx, [ebp + EXTFS.block_size]
|
||
|
||
@@:
|
||
mov eax, [ebx]
|
||
test eax, eax
|
||
jz .complete
|
||
|
||
call ext2_block_free
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
add ebx, 4
|
||
cmp ebx, edx
|
||
jb @B
|
||
|
||
.success:
|
||
xor eax, eax
|
||
.ret:
|
||
pop edx ebx
|
||
ret
|
||
|
||
.complete:
|
||
xor eax, eax
|
||
inc eax
|
||
jmp .ret
|
||
|
||
.fail:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Frees all indirect blocks.
|
||
; Input: ebp = pointer to EXTFS.
|
||
; [ebp + EXTFS.ext2_save_inode] = the inode.
|
||
; Output: eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_free_indirect_blocks:
|
||
push edi
|
||
|
||
mov edi, [ebp + EXTFS.ext2_save_inode]
|
||
|
||
; Free indirect block.
|
||
mov eax, [edi + EXT2_INODE_STRUC.i_block + 12*4]
|
||
test eax, eax
|
||
jz .success
|
||
|
||
call ext2_block_free
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov eax, [edi + EXT2_INODE_STRUC.i_block + 13*4]
|
||
call ext2_inode_free_doubly_indirect
|
||
cmp eax, 1
|
||
je .success
|
||
cmp eax, 0xFFFFFFFF
|
||
je .fail
|
||
|
||
mov eax, [edi + EXT2_INODE_STRUC.i_block + 14*4]
|
||
call ext2_inode_free_triply_indirect
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
.success:
|
||
xor eax, eax
|
||
.ret:
|
||
pop edi
|
||
ret
|
||
|
||
.fail:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Allocates block for inode.
|
||
; Input: esi = address of inode
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_calloc_block:
|
||
push ecx
|
||
|
||
; TODO: fix to have correct preference.
|
||
mov eax, EXT2_ROOT_INO
|
||
call ext2_block_calloc
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
|
||
mov eax, 2
|
||
shl eax, cl
|
||
add [esi + EXT2_INODE_STRUC.i_blocks], eax
|
||
|
||
.success:
|
||
xor eax, eax
|
||
.ret:
|
||
pop ecx
|
||
ret
|
||
|
||
.fail:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Sets block ID for indirect-addressing inode.
|
||
; Input: ecx = index of block in inode
|
||
; edi = block ID to set to
|
||
; esi = address of inode
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_set_block:
|
||
push ebx ecx edx
|
||
|
||
; 0 to 11: direct blocks.
|
||
cmp ecx, 12
|
||
jb .direct_block
|
||
|
||
; Indirect blocks
|
||
sub ecx, 12
|
||
cmp ecx, [ebp + EXTFS.count_pointer_in_block]
|
||
jb .indirect_block
|
||
|
||
; Double indirect blocks.
|
||
sub ecx, [ebp + EXTFS.count_pointer_in_block]
|
||
cmp ecx, [ebp + EXTFS.count_pointer_in_block_square]
|
||
jb .double_indirect_block
|
||
|
||
; Triple indirect blocks.
|
||
sub ecx, [ebp + EXTFS.count_pointer_in_block_square]
|
||
|
||
; Get triply-indirect block in temp_block.
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
|
||
test eax, eax
|
||
jnz @F
|
||
|
||
call ext2_inode_calloc_block
|
||
test eax, eax
|
||
jnz .fail_alloc
|
||
|
||
mov [esi + EXT2_INODE_STRUC.i_block + 14*4], ebx
|
||
mov eax, ebx
|
||
|
||
@@:
|
||
push eax
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail_alloc_4
|
||
|
||
; Get index in triply-indirect block.
|
||
xor edx, edx
|
||
mov eax, ecx
|
||
div [ebp + EXTFS.count_pointer_in_block_square]
|
||
|
||
; eax: index in triply-indirect block, edx: index in doubly-indirect block.
|
||
lea ecx, [ebx + eax*4]
|
||
mov eax, [ebx + eax*4]
|
||
test eax, eax
|
||
jnz @F
|
||
|
||
call ext2_inode_calloc_block
|
||
test eax, eax
|
||
jnz .fail_alloc_4
|
||
|
||
mov [ecx], ebx
|
||
|
||
mov eax, [esp]
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .fail_alloc_4
|
||
|
||
mov eax, [ecx]
|
||
@@:
|
||
mov [esp], eax
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail_alloc_4
|
||
|
||
mov eax, edx
|
||
jmp @F
|
||
|
||
.double_indirect_block:
|
||
; Get doubly-indirect block.
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
|
||
test eax, eax
|
||
jnz .double_indirect_present
|
||
|
||
call ext2_inode_calloc_block
|
||
test eax, eax
|
||
jnz .fail_alloc
|
||
|
||
mov [esi + EXT2_INODE_STRUC.i_block + 13*4], ebx
|
||
mov eax, ebx
|
||
|
||
.double_indirect_present:
|
||
; Save block we're at.
|
||
push eax
|
||
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail_alloc_4
|
||
|
||
mov eax, ecx
|
||
@@:
|
||
xor edx, edx
|
||
div [ebp + EXTFS.count_pointer_in_block]
|
||
|
||
; eax: index in doubly-indirect block, edx: index in indirect block.
|
||
lea ecx, [ebx + edx*4]
|
||
push ecx
|
||
|
||
lea ecx, [ebx + eax*4]
|
||
cmp dword[ecx], 0
|
||
jne @F
|
||
|
||
call ext2_inode_calloc_block
|
||
test eax, eax
|
||
jnz .fail_alloc_8
|
||
|
||
mov [ecx], ebx
|
||
|
||
mov eax, [esp + 4]
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .fail_alloc_8
|
||
|
||
@@:
|
||
mov eax, [ecx]
|
||
push eax
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail_alloc_12
|
||
|
||
pop eax
|
||
pop ecx
|
||
mov [ecx], edi
|
||
call ext2_block_write
|
||
|
||
add esp, 4
|
||
jmp .return
|
||
|
||
.indirect_block:
|
||
; Get index of indirect block.
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
|
||
test eax, eax
|
||
jnz @F
|
||
|
||
call ext2_inode_calloc_block
|
||
test eax, eax
|
||
jnz .fail_alloc
|
||
|
||
mov [esi + EXT2_INODE_STRUC.i_block + 12*4], ebx
|
||
mov eax, ebx
|
||
|
||
@@:
|
||
push eax
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail_alloc_4
|
||
|
||
; Get the block ID.
|
||
mov [ebx + ecx*4], edi
|
||
pop eax
|
||
call ext2_block_write
|
||
jmp .return
|
||
|
||
.direct_block:
|
||
mov [esi + EXT2_INODE_STRUC.i_block + ecx*4], edi
|
||
xor eax, eax
|
||
|
||
.return:
|
||
pop edx ecx ebx
|
||
ret
|
||
|
||
.fail_alloc:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .return
|
||
|
||
.fail_alloc_12:
|
||
add esp, 4
|
||
.fail_alloc_8:
|
||
add esp, 4
|
||
.fail_alloc_4:
|
||
add esp, 4
|
||
jmp .fail_alloc
|
||
|
||
;---------------------------------------------------------------------
|
||
; Receives block ID from indirect-addressing inode.
|
||
; Input: ecx = index of block in inode
|
||
; esi = address of inode
|
||
; ebp = pointer to EXTFS
|
||
; Output: ecx = block ID, if successful
|
||
; eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_get_block:
|
||
; If inode is extent-based, use ext4_block_recursive_search.
|
||
test [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
|
||
jz @F
|
||
|
||
pushad
|
||
|
||
; Get extent header in EBP.
|
||
add esi, EXT2_INODE_STRUC.i_block
|
||
call ext4_block_recursive_search
|
||
mov PUSHAD_ECX, ecx
|
||
mov PUSHAD_EAX, eax
|
||
|
||
popad
|
||
ret
|
||
|
||
@@:
|
||
; 0 to 11: direct blocks.
|
||
cmp ecx, 12
|
||
jb .get_direct_block
|
||
|
||
; Indirect blocks
|
||
sub ecx, 12
|
||
cmp ecx, [ebp + EXTFS.count_pointer_in_block]
|
||
jb .get_indirect_block
|
||
|
||
; Double indirect blocks.
|
||
sub ecx, [ebp + EXTFS.count_pointer_in_block]
|
||
cmp ecx, [ebp + EXTFS.count_pointer_in_block_square]
|
||
jb .get_double_indirect_block
|
||
|
||
; Triple indirect blocks.
|
||
sub ecx, [ebp + EXTFS.count_pointer_in_block_square]
|
||
push edx ebx
|
||
|
||
; Get triply-indirect block in temp_block.
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
; Get index in triply-indirect block.
|
||
xor edx, edx
|
||
mov eax, ecx
|
||
div [ebp + EXTFS.count_pointer_in_block_square]
|
||
|
||
; eax: index in triply-indirect block, edx: index in doubly-indirect block.
|
||
mov eax, [ebx + eax*4]
|
||
test eax, eax
|
||
jz .fail_triple_indirect_block
|
||
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov eax, edx
|
||
jmp @F
|
||
|
||
.get_double_indirect_block:
|
||
push edx ebx
|
||
|
||
; Get doubly-indirect block.
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
|
||
test eax, eax
|
||
jz .fail_double_indirect_block
|
||
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov eax, ecx
|
||
@@:
|
||
xor edx, edx
|
||
div [ebp + EXTFS.count_pointer_in_block]
|
||
|
||
; eax: index in doubly-indirect block, edx: index in indirect block.
|
||
mov eax, [ebx + eax*4]
|
||
test eax, eax
|
||
jz .fail_double_indirect_block
|
||
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov ecx, [ebx + edx*4]
|
||
.fail:
|
||
pop ebx edx
|
||
|
||
ret
|
||
|
||
.get_indirect_block:
|
||
push ebx
|
||
|
||
; Get index of indirect block.
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
|
||
test eax, eax
|
||
jz .fail_indirect_block
|
||
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz @F
|
||
|
||
mov ecx, [ebx + ecx*4]
|
||
@@:
|
||
pop ebx
|
||
|
||
ret
|
||
|
||
.get_direct_block:
|
||
mov ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4]
|
||
xor eax, eax
|
||
|
||
ret
|
||
|
||
.fail_indirect_block:
|
||
pop ebx
|
||
|
||
.fail_triple_indirect_block:
|
||
xor eax, eax
|
||
xor ecx, ecx
|
||
ret
|
||
|
||
.fail_double_indirect_block:
|
||
pop ebx edx
|
||
jmp .fail_triple_indirect_block
|
||
|
||
;---------------------------------------------------------------------
|
||
; Get block containing inode.
|
||
; Input: eax = inode number.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: ebx = block (hard disk) containing inode.
|
||
; edx = index inside block.
|
||
; eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_read_block_of_inode:
|
||
pushad
|
||
|
||
dec eax
|
||
xor edx, edx
|
||
|
||
; EAX = block group.
|
||
div [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
|
||
|
||
push edx ; Index in group.
|
||
|
||
mov edx, 32
|
||
mul edx ; Get index of descriptor in global_desc_table.
|
||
|
||
; eax: inode group offset relative to global descriptor table start
|
||
; Find the block this block descriptor is in.
|
||
div [ebp + EXTFS.block_size]
|
||
add eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block]
|
||
inc eax
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .return
|
||
|
||
add ebx, edx ; edx: local index of descriptor inside block
|
||
mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table] ; Block number of inode table - in ext2 terms.
|
||
mov ecx, [ebp + EXTFS.log_block_size]
|
||
shl eax, cl
|
||
|
||
; eax: points to inode table on HDD.
|
||
mov esi, eax
|
||
|
||
; Add local address of inode.
|
||
pop eax
|
||
mov ecx, [ebp + EXTFS.inode_size]
|
||
mul ecx ; (index * inode_size)
|
||
|
||
mov ebp, 512
|
||
div ebp ; Divide by hard disk block size.
|
||
|
||
add eax, esi ; Found block to read.
|
||
mov ebx, eax ; Get it inside ebx.
|
||
|
||
xor eax, eax
|
||
.return:
|
||
mov PUSHAD_EAX, eax
|
||
mov PUSHAD_EBX, ebx
|
||
mov PUSHAD_EDX, edx
|
||
|
||
popad
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Sets content of inode by number.
|
||
; Input: eax = inode number.
|
||
; ebx = address from where to write inode content.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_write:
|
||
push edx edi esi ecx ebx
|
||
mov esi, ebx
|
||
|
||
; Ext2 actually stores time of modification of inode in ctime.
|
||
lea edi, [ebx + EXT2_INODE_STRUC.i_ctime]
|
||
call current_unix_time
|
||
|
||
; Get block where inode is situated.
|
||
call ext2_read_block_of_inode
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov eax, ebx ; Get block into EAX.
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
|
||
mov ecx, eax ; Save block.
|
||
call fs_read32_sys
|
||
test eax, eax
|
||
jz @F
|
||
|
||
.error:
|
||
mov eax, ERROR_DEVICE
|
||
jmp .return
|
||
|
||
@@:
|
||
mov eax, ecx
|
||
mov ecx, [ebp + EXTFS.inode_size]
|
||
mov edi, edx ; The index into the block.
|
||
add edi, ebx
|
||
rep movsb
|
||
|
||
; Write the block.
|
||
call fs_write32_sys
|
||
|
||
.return:
|
||
pop ebx ecx esi edi edx
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Get content of inode by number.
|
||
; Input: eax = inode number.
|
||
; ebx = address where to store inode content.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code (0 implies no error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_read:
|
||
push edx edi esi ecx ebx
|
||
mov edi, ebx
|
||
|
||
; Get block where inode is situated.
|
||
call ext2_read_block_of_inode
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov eax, ebx ; Get block into EAX.
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call fs_read32_sys
|
||
test eax, eax
|
||
jz @F
|
||
|
||
.error:
|
||
mov eax, ERROR_DEVICE
|
||
jmp .return
|
||
|
||
@@:
|
||
mov ecx, [ebp + EXTFS.inode_size]
|
||
mov esi, edx ; The index into the inode.
|
||
add esi, ebx
|
||
rep movsb
|
||
|
||
xor eax, eax
|
||
.return:
|
||
pop ebx ecx esi edi edx
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Seek inode from the path.
|
||
; Input: esi + [esp + 4] = name.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code (0 implies no error)
|
||
; esi = inode number.
|
||
; dl = first byte of file/folder name.
|
||
; [ext2_data.ext2_save_inode] stores the inode.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_find:
|
||
mov edx, [ebp + EXTFS.root_inode]
|
||
|
||
; Check for empty root.
|
||
cmp [edx + EXT2_INODE_STRUC.i_blocks], 0
|
||
je .error_empty_root
|
||
|
||
; Check for root.
|
||
cmp byte[esi], 0
|
||
jne .next_path_part
|
||
|
||
push edi ecx
|
||
mov esi, [ebp + EXTFS.root_inode]
|
||
mov edi, [ebp + EXTFS.ext2_save_inode]
|
||
mov ecx, [ebp + EXTFS.inode_size]
|
||
rep movsb
|
||
pop ecx edi
|
||
|
||
xor eax, eax
|
||
xor dl, dl
|
||
mov esi, EXT2_ROOT_INO
|
||
ret 4
|
||
|
||
.next_path_part:
|
||
push [edx + EXT2_INODE_STRUC.i_blocks]
|
||
xor ecx, ecx
|
||
|
||
.folder_block_cycle:
|
||
push ecx
|
||
xchg esi, edx
|
||
call ext2_inode_get_block
|
||
xchg esi, edx
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
|
||
mov eax, ecx
|
||
mov ebx, [ebp + EXTFS.ext2_save_block] ; Get directory records from directory.
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .error_get_block
|
||
|
||
push esi
|
||
push edx
|
||
call ext2_block_find_parent
|
||
pop edx
|
||
pop edi ecx
|
||
|
||
cmp edi, esi ; Did something match?
|
||
je .next_folder_block ; No, move to next block.
|
||
|
||
cmp byte [esi], 0 ; Reached the "end" of path successfully.
|
||
jnz @F
|
||
cmp dword[esp + 8], 0
|
||
je .get_inode_ret
|
||
mov esi, [esp + 8]
|
||
mov dword[esp + 8], 0
|
||
|
||
@@:
|
||
mov eax, [ebx + EXT2_DIR_STRUC.inode]
|
||
mov ebx, [ebp + EXTFS.ext2_save_inode]
|
||
call ext2_inode_read
|
||
test eax, eax
|
||
jnz .error_get_inode
|
||
|
||
movzx eax, [ebx + EXT2_INODE_STRUC.i_mode]
|
||
and eax, EXT2_S_IFMT ; Get the mask.
|
||
cmp eax, EXT2_S_IFDIR
|
||
jne .not_found ; Matched till part, but directory entry we got doesn't point to folder.
|
||
|
||
pop ecx ; Stack top contains number of blocks.
|
||
mov edx, ebx
|
||
jmp .next_path_part
|
||
|
||
.next_folder_block:
|
||
; Next block in current folder.
|
||
pop eax ; Get blocks counter.
|
||
sub eax, [ebp + EXTFS.count_block_in_block]
|
||
jle .not_found
|
||
|
||
push eax
|
||
inc ecx
|
||
jmp .folder_block_cycle
|
||
|
||
.not_found:
|
||
mov eax, ERROR_FILE_NOT_FOUND
|
||
ret 4
|
||
|
||
.get_inode_ret:
|
||
pop ecx ; Stack top contains number of blocks.
|
||
|
||
mov dl, [ebx + EXT2_DIR_STRUC.name] ; First character of file-name.
|
||
mov eax, [ebx + EXT2_DIR_STRUC.inode]
|
||
mov ebx, [ebp + EXTFS.ext2_save_inode]
|
||
mov esi, eax
|
||
|
||
; If we can't get the inode, eax contains the error.
|
||
call ext2_inode_read
|
||
ret 4
|
||
|
||
.error_get_inode_block:
|
||
.error_get_block:
|
||
pop ecx
|
||
.error_get_inode:
|
||
pop ebx
|
||
.error_empty_root:
|
||
mov eax, ERROR_FS_FAIL
|
||
ret 4
|
||
|
||
;---------------------------------------------------------------------
|
||
; Seeks parent inode from path.
|
||
; Input: esi = path.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code.
|
||
; esi = inode.
|
||
; edi = pointer to file name.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_find_parent:
|
||
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
|
||
|
||
; If it was just a filename (without any additional directories),
|
||
; use the last byte as "parent path".
|
||
cmp edi, 0
|
||
jne @F
|
||
|
||
pop edi
|
||
dec esi
|
||
jmp .get_inode
|
||
|
||
; It had some additional directories, so handle it that way.
|
||
@@:
|
||
mov byte[edi], 0
|
||
inc edi
|
||
pop esi
|
||
|
||
.get_inode:
|
||
push ebx edx
|
||
stdcall ext2_inode_find, 0
|
||
pop edx ebx
|
||
|
||
.return:
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Link an inode.
|
||
; Input: eax = inode on which to link.
|
||
; ebx = inode to link.
|
||
; dl = file type.
|
||
; esi = name.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_link:
|
||
push eax
|
||
push esi edi ebx ecx edx
|
||
|
||
; Get string length, and then directory entry structure size.
|
||
call strlen
|
||
add ecx, 8
|
||
|
||
push esi ebx ecx
|
||
|
||
xor ecx, ecx
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
mov ebx, esi
|
||
|
||
call ext2_inode_read
|
||
test eax, eax
|
||
jnz .error_inode_read
|
||
|
||
; Get the maximum addressible i_block index by (i_blocks/(2 << s_log_block_size)).
|
||
; Note that i_blocks contains number of reserved 512B blocks, which is why we've to
|
||
; find out the ext2 blocks.
|
||
mov eax, 2
|
||
mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
|
||
shl eax, cl
|
||
mov ecx, eax
|
||
|
||
mov eax, [esi + EXT2_INODE_STRUC.i_blocks]
|
||
xor edx, edx
|
||
|
||
div ecx
|
||
|
||
; EAX is the maximum index inside i_block we can go.
|
||
push eax
|
||
push dword 0
|
||
|
||
; ECX contains the "block inside i_block" index.
|
||
xor ecx, ecx
|
||
@@:
|
||
call ext2_inode_get_block
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
test ecx, ecx
|
||
jz .alloc_block ; We've got no block here, so allocate one.
|
||
|
||
push ecx ; Save block number.
|
||
|
||
mov eax, ecx
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .error_block_read
|
||
|
||
; Try to find free space in current block.
|
||
mov ecx, [esp + 8]
|
||
call ext2_block_find_fspace
|
||
test eax, eax
|
||
jz .found
|
||
|
||
cmp eax, 0x00000001
|
||
jne .next_iter
|
||
|
||
; This block wasn't linking to the next block, so fix that, and use the next one.
|
||
; Write the block.
|
||
pop eax
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
|
||
inc dword [esp]
|
||
mov ecx, [esp]
|
||
call ext2_inode_get_block
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
|
||
test ecx, ecx
|
||
jz .alloc_block
|
||
|
||
; If there was a block there, prepare it for our use!
|
||
push ecx
|
||
jmp .prepare_block
|
||
|
||
.next_iter:
|
||
add esp, 4
|
||
|
||
inc dword [esp]
|
||
mov ecx, [esp]
|
||
cmp ecx, [esp + 4]
|
||
jbe @B
|
||
|
||
.alloc_block:
|
||
mov eax, [esp + 12] ; Get inode ID of what we're linking.
|
||
call ext2_block_calloc
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
|
||
mov ecx, [esp] ; Get the index of it inside the inode.
|
||
mov edi, ebx ; And what to set to.
|
||
call ext2_inode_set_block
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
|
||
; Update i_size.
|
||
mov eax, [ebp + EXTFS.block_size]
|
||
add [esi + EXT2_INODE_STRUC.i_size], eax
|
||
|
||
; Update i_blocks.
|
||
mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
|
||
mov eax, 2
|
||
shl eax, cl
|
||
add [esi + EXT2_INODE_STRUC.i_blocks], eax
|
||
|
||
; Write the inode.
|
||
mov eax, [esp + 40]
|
||
mov ebx, esi
|
||
call ext2_inode_write
|
||
test eax, eax
|
||
jnz .error_get_inode_block
|
||
|
||
push edi ; Save the block we just allocated.
|
||
|
||
; If we've allocated/using-old-block outside of loop, prepare it.
|
||
.prepare_block:
|
||
mov eax, [esp]
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .error_block_read
|
||
|
||
mov edi, ebx
|
||
mov eax, [ebp + EXTFS.block_size]
|
||
mov [edi + EXT2_DIR_STRUC.rec_len], ax
|
||
|
||
.found:
|
||
pop edx
|
||
add esp, 8
|
||
pop ecx ebx esi
|
||
|
||
push ebx
|
||
mov [edi], ebx ; Save inode.
|
||
|
||
mov eax, [esp + 4] ; Get EDX off the stack -- contains the file_type.
|
||
cmp [ebp + EXTFS.superblock + EXT2_SB_STRUC.rev_level], EXT2_GOOD_OLD_REV
|
||
je .name
|
||
|
||
; Set the file-type.
|
||
mov [edi + EXT2_DIR_STRUC.file_type], al
|
||
|
||
.name:
|
||
; Save name.
|
||
sub ecx, 8
|
||
mov [edi + EXT2_DIR_STRUC.name_len], cl
|
||
add edi, 8
|
||
rep movsb
|
||
|
||
; Write block.
|
||
mov eax, edx
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .error_block_write
|
||
|
||
mov eax, [esp]
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_read
|
||
test eax, eax
|
||
jnz .error_block_write
|
||
|
||
pop eax
|
||
inc [ebx + EXT2_INODE_STRUC.i_links_count]
|
||
call ext2_inode_write
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
xor eax, eax
|
||
.ret:
|
||
pop edx ecx ebx edi esi
|
||
add esp, 4
|
||
ret
|
||
|
||
.error_block_read:
|
||
add esp, 4
|
||
.error_get_inode_block:
|
||
add esp, 8
|
||
.error_inode_read:
|
||
add esp, 8
|
||
.error_block_write:
|
||
add esp, 4
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Unlink an inode.
|
||
; Input: eax = inode from which to unlink.
|
||
; ebx = inode to unlink.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = number of links to inode, after unlinking (0xFFFFFFFF implies error)
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_unlink:
|
||
push ebx ecx edx esi edi
|
||
|
||
push ebx
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_read
|
||
|
||
test eax, eax
|
||
jnz .fail_get_inode
|
||
|
||
; The index into the inode block data.
|
||
push dword 0
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
|
||
.loop:
|
||
mov ecx, [esp]
|
||
call ext2_inode_get_block
|
||
|
||
test eax, eax
|
||
jnz .fail_loop
|
||
test ecx, ecx
|
||
jz .fail_loop
|
||
|
||
mov eax, ecx
|
||
mov edi, eax
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .fail_loop
|
||
|
||
; edi -> block.
|
||
.first_dir_entry:
|
||
mov eax, [esp + 4]
|
||
cmp [ebx], eax
|
||
jne @F
|
||
|
||
mov dword[ebx], 0 ; inode.
|
||
mov word[ebx + 6], 0 ; name_len + file_type.
|
||
jmp .write_block
|
||
|
||
@@:
|
||
mov edx, ebx
|
||
add edx, [ebp + EXTFS.block_size]
|
||
push edx
|
||
|
||
mov edx, ebx
|
||
movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len]
|
||
add ebx, ecx
|
||
|
||
.dir_entry:
|
||
cmp [ebx], eax
|
||
jne @F
|
||
|
||
mov cx, [ebx + EXT2_DIR_STRUC.rec_len]
|
||
add [edx + EXT2_DIR_STRUC.rec_len], cx
|
||
add esp, 4
|
||
jmp .write_block
|
||
|
||
@@:
|
||
mov edx, ebx
|
||
movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len]
|
||
|
||
; If it's a zero length entry, error.
|
||
test ecx, ecx
|
||
jz .fail_inode
|
||
|
||
add ebx, ecx
|
||
|
||
cmp ebx, [esp]
|
||
jb .dir_entry
|
||
|
||
add esp, 4
|
||
inc dword[esp]
|
||
jmp .loop
|
||
|
||
.write_block:
|
||
mov eax, edi
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .fail_loop
|
||
|
||
add esp, 4
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
mov eax, [esp]
|
||
call ext2_inode_read
|
||
test eax, eax
|
||
jnz .fail_get_inode
|
||
|
||
dec word[ebx + EXT2_INODE_STRUC.i_links_count]
|
||
movzx eax, word[ebx + EXT2_INODE_STRUC.i_links_count]
|
||
push eax
|
||
|
||
mov eax, [esp + 4]
|
||
call ext2_inode_write
|
||
test eax, eax
|
||
jnz .fail_loop
|
||
|
||
pop eax
|
||
add esp, 4
|
||
.return:
|
||
pop edi esi edx ecx ebx
|
||
ret
|
||
|
||
.fail_inode:
|
||
add esp, 4
|
||
|
||
.fail_loop:
|
||
add esp, 4
|
||
|
||
.fail_get_inode:
|
||
add esp, 4
|
||
|
||
.fail:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .return
|
||
|
||
;---------------------------------------------------------------------
|
||
; Checks if a directory is empty.
|
||
; Input: ebx = inode to check.
|
||
; ebp = pointer to EXTFS.
|
||
; [EXTFS.ext2_save_inode] = points to saved inode.
|
||
; Output: eax = 0 signifies empty directory.
|
||
;---------------------------------------------------------------------
|
||
ext2_dir_empty:
|
||
push ebx ecx edx
|
||
|
||
; The index into the inode block data.
|
||
push dword 0
|
||
mov esi, [ebp + EXTFS.ext2_save_inode]
|
||
|
||
.loop:
|
||
mov ecx, [esp]
|
||
call ext2_inode_get_block
|
||
|
||
; Treat a failure as not-empty.
|
||
test eax, eax
|
||
jnz .not_empty
|
||
test ecx, ecx
|
||
jz .empty
|
||
|
||
mov eax, ecx
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .not_empty
|
||
|
||
mov edx, ebx
|
||
add edx, [ebp + EXTFS.block_size]
|
||
|
||
movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len]
|
||
add ebx, ecx
|
||
|
||
.dir_entry:
|
||
; Process entry.
|
||
cmp byte[ebx + EXT2_DIR_STRUC.name_len], 1
|
||
jne @F
|
||
|
||
cmp byte[ebx + EXT2_DIR_STRUC.name], '.'
|
||
jne .not_empty
|
||
|
||
@@:
|
||
cmp byte[ebx + EXT2_DIR_STRUC.name_len], 2
|
||
jne .not_empty
|
||
|
||
cmp word[ebx + EXT2_DIR_STRUC.name], '..'
|
||
jne .not_empty
|
||
|
||
@@:
|
||
movzx ecx, [ebx + EXT2_DIR_STRUC.rec_len]
|
||
add ebx, ecx
|
||
|
||
cmp ebx, edx
|
||
jb .dir_entry
|
||
|
||
inc dword[esp]
|
||
jmp .loop
|
||
|
||
.empty:
|
||
xor eax, eax
|
||
.return:
|
||
add esp, 4
|
||
pop edx ecx ebx
|
||
ret
|
||
|
||
.not_empty:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .return
|
||
|
||
;---------------------------------------------------------------------
|
||
; Gets the block group's inode bitmap.
|
||
; Input: eax = block group.
|
||
; Output: eax = if zero, error; else, points to block group descriptor.
|
||
; ebx = inode bitmap's block (hard disk).
|
||
;---------------------------------------------------------------------
|
||
ext2_bg_read_inode_bitmap:
|
||
push ecx
|
||
|
||
call ext2_bg_read_desc
|
||
test eax, eax
|
||
jz .fail
|
||
|
||
mov ebx, [eax + EXT2_BLOCK_GROUP_DESC.inode_bitmap] ; Block number of inode bitmap - in ext2 terms.
|
||
|
||
.return:
|
||
pop ecx
|
||
ret
|
||
|
||
.fail:
|
||
xor eax, eax
|
||
jmp .return
|
||
|
||
;---------------------------------------------------------------------
|
||
; Allocates a inode.
|
||
; Input: eax = inode ID for "preference".
|
||
; ebp = pointer to EXTFS.
|
||
; Output: Inode marked as set in inode group.
|
||
; eax = error code.
|
||
; ebx = inode ID.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_alloc:
|
||
push [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_count]
|
||
push EXT2_BLOCK_GROUP_DESC.free_inodes_count
|
||
push [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
|
||
|
||
lea ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_inodes_count]
|
||
push ebx
|
||
|
||
push ext2_bg_read_inode_bitmap
|
||
|
||
call ext2_resource_alloc
|
||
|
||
; Inode table starts with 1.
|
||
inc ebx
|
||
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Frees a inode.
|
||
; Input: eax = inode ID.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: inode marked as free in block group.
|
||
; eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_free:
|
||
push edi ecx
|
||
|
||
; Inode table starts with 1.
|
||
dec eax
|
||
|
||
mov edi, ext2_bg_read_inode_bitmap
|
||
xor ecx, ecx
|
||
inc cl
|
||
call ext2_resource_free
|
||
|
||
pop ecx edi
|
||
ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Blanks a particular entry in an inode.
|
||
; Input: eax = index into block.
|
||
; edx = inode.
|
||
; ebp = pointer to EXTFS.
|
||
; [ebp + EXTFS.ext2_temp_inode] = the inode.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_blank_entry:
|
||
push ebx ecx edx edi esi
|
||
|
||
mov edi, eax
|
||
|
||
mov ecx, eax
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_get_block
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
test ecx, ecx
|
||
jz .allocate
|
||
|
||
mov edx, ecx
|
||
mov ecx, [ebp + EXTFS.block_size]
|
||
mov edi, [ebp + EXTFS.ext2_temp_block]
|
||
xor eax, eax
|
||
rep stosb
|
||
|
||
mov eax, edx
|
||
mov ebx, [ebp + EXTFS.ext2_temp_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
jmp .success
|
||
|
||
; Need to allocate a block.
|
||
.allocate:
|
||
mov eax, edx
|
||
call ext2_block_calloc
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov ecx, edi
|
||
mov edi, ebx
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_set_block
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
|
||
mov eax, 2
|
||
shl eax, cl
|
||
add [esi + EXT2_INODE_STRUC.i_blocks], eax
|
||
|
||
.success:
|
||
xor eax, eax
|
||
|
||
.ret:
|
||
pop esi edi edx ecx ebx
|
||
ret
|
||
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Frees a particular entry in an inode.
|
||
; Input: eax = index into block.
|
||
; ebp = pointer to EXTFS.
|
||
; [ebp + EXTFS.ext2_temp_inode] = the inode.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_free_entry:
|
||
push ebx ecx edi esi
|
||
|
||
mov edi, eax
|
||
|
||
mov ecx, eax
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_get_block
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
test ecx, ecx
|
||
jz .success
|
||
|
||
mov eax, ecx
|
||
call ext2_block_free
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov ecx, edi
|
||
xor edi, edi
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_set_block
|
||
|
||
mov ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
|
||
mov eax, 2
|
||
shl eax, cl
|
||
sub [esi + EXT2_INODE_STRUC.i_blocks], eax
|
||
|
||
.success:
|
||
xor eax, eax
|
||
|
||
.ret:
|
||
pop esi edi ecx ebx
|
||
ret
|
||
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Reads a particular entry from an inode.
|
||
; Input: eax = index into block.
|
||
; ebp = pointer to EXTFS.
|
||
; [ebp + EXTFS.ext2_temp_inode] = the inode.
|
||
; Output: eax = error code.
|
||
; [ebp + EXTFS.ext2_save_block] = the read block.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_read_entry:
|
||
push ebx ecx edx esi
|
||
|
||
mov ecx, eax
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_get_block
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
test ecx, ecx
|
||
jz .error
|
||
|
||
mov eax, ecx
|
||
mov ebx, [ebp + EXTFS.ext2_save_block]
|
||
call ext2_block_read
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
.ret:
|
||
pop esi edx ecx ebx
|
||
ret
|
||
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Writes a particular entry from an inode.
|
||
; Input: eax = index into block.
|
||
; ebp = pointer to EXTFS.
|
||
; [ebp + EXTFS.ext2_temp_inode] = the inode.
|
||
; [ebp + EXTFS.ext2_save_block] = the block to write.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_write_entry:
|
||
push ebx ecx edx esi
|
||
|
||
mov ecx, eax
|
||
mov esi, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_get_block
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
test ecx, ecx
|
||
jz .error
|
||
|
||
mov eax, ecx
|
||
mov ebx, [ebp + EXTFS.ext2_save_block]
|
||
call ext2_block_write
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
.ret:
|
||
pop esi edx ecx ebx
|
||
ret
|
||
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Extends inode to said size.
|
||
; Input: eax = inode ID.
|
||
; ecx = size to extend to.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_extend:
|
||
push ebx ecx edx esi edi
|
||
|
||
; Save the inode.
|
||
push eax
|
||
|
||
; Read the inode.
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_read
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov eax, [ebx + EXT2_INODE_STRUC.i_size]
|
||
cmp eax, ecx
|
||
jge .success
|
||
|
||
; Save the size of the inode.
|
||
push eax
|
||
|
||
; ECX contains the size we've to write.
|
||
sub ecx, eax
|
||
xor edx, edx
|
||
div [ebp + EXTFS.block_size]
|
||
|
||
test edx, edx
|
||
jz .start_aligned
|
||
|
||
; Start isn't aligned, so deal with the non-aligned bytes.
|
||
mov esi, [ebp + EXTFS.block_size]
|
||
sub esi, edx
|
||
|
||
cmp esi, ecx
|
||
jbe @F
|
||
|
||
; If the size to entend to fits in current block, limit to that.
|
||
mov esi, ecx
|
||
|
||
@@:
|
||
; Clear ESI bytes, in EAX indexed block.
|
||
push eax
|
||
call ext2_inode_read_entry
|
||
test eax, eax
|
||
pop eax
|
||
jnz .error_inode_size
|
||
|
||
push eax ecx
|
||
|
||
xor eax, eax
|
||
mov ecx, esi
|
||
mov edi, ebx
|
||
add edi, edx
|
||
|
||
rep stosb
|
||
|
||
pop ecx eax
|
||
|
||
; Write the block.
|
||
call ext2_inode_write_entry
|
||
test eax, eax
|
||
jnz .error_inode_size
|
||
|
||
add [esp], esi
|
||
sub ecx, esi
|
||
jz .write_inode
|
||
|
||
.start_aligned:
|
||
cmp ecx, [ebp + EXTFS.block_size]
|
||
jb @F
|
||
|
||
mov eax, [esp]
|
||
xor edx, edx
|
||
div [ebp + EXTFS.block_size]
|
||
|
||
mov edx, [esp + 4]
|
||
call ext2_inode_blank_entry
|
||
|
||
test eax, eax
|
||
jnz .error_inode_size
|
||
|
||
mov eax, [ebp + EXTFS.block_size]
|
||
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.block_size]
|
||
|
||
mov edx, [esp + 4]
|
||
call ext2_inode_blank_entry
|
||
|
||
test eax, eax
|
||
jnz .error_inode_size
|
||
add [esp], ecx
|
||
|
||
.write_inode:
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
pop eax
|
||
mov [ebx + EXT2_INODE_STRUC.i_size], eax
|
||
mov eax, [esp]
|
||
call ext2_inode_write
|
||
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
.success:
|
||
xor eax, eax
|
||
|
||
.ret:
|
||
add esp, 4
|
||
|
||
pop edi esi edx ecx ebx
|
||
ret
|
||
|
||
.error_inode_size:
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
pop eax
|
||
mov [ebx + EXT2_INODE_STRUC.i_size], eax
|
||
mov eax, [esp]
|
||
call ext2_inode_write
|
||
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|
||
|
||
;---------------------------------------------------------------------
|
||
; Truncates inode to said size.
|
||
; Input: eax = inode ID.
|
||
; ecx = size to truncate to.
|
||
; ebp = pointer to EXTFS.
|
||
; Output: eax = error code.
|
||
;---------------------------------------------------------------------
|
||
ext2_inode_truncate:
|
||
push ebx ecx edx esi edi
|
||
|
||
; Save the inode.
|
||
push eax
|
||
|
||
; Read the inode.
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
call ext2_inode_read
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
mov eax, [ebx + EXT2_INODE_STRUC.i_size]
|
||
cmp ecx, eax
|
||
jge .success
|
||
|
||
; Save the size of the inode.
|
||
push eax
|
||
|
||
; ECX contains the size we've to truncate.
|
||
sub ecx, eax
|
||
not ecx
|
||
inc ecx
|
||
xor edx, edx
|
||
div [ebp + EXTFS.block_size]
|
||
|
||
test edx, edx
|
||
jz .start_aligned
|
||
|
||
; Start isn't aligned, so deal with the non-aligned bytes.
|
||
mov esi, edx
|
||
|
||
cmp esi, ecx
|
||
jbe @F
|
||
|
||
; If the size to truncate is smaller than the un-aligned bytes
|
||
; we're going to have to mark neccessary bytes from the EOF
|
||
; as 0.
|
||
push eax
|
||
call ext2_inode_read_entry
|
||
test eax, eax
|
||
pop eax
|
||
jnz .error_inode_size
|
||
|
||
mov edi, [ebp + EXTFS.ext2_save_block]
|
||
sub edx, ecx
|
||
add edi, edx
|
||
|
||
push ecx eax
|
||
xor eax, eax
|
||
rep stosb
|
||
pop eax ecx
|
||
|
||
call ext2_inode_write_entry
|
||
test eax, eax
|
||
jnz .error_inode_size
|
||
|
||
sub [esp], ecx
|
||
jmp .write_inode
|
||
|
||
@@:
|
||
; Since ECX is greater than or equal to the bytes here un-aligned
|
||
; just free the block.
|
||
call ext2_inode_free_entry
|
||
|
||
sub [esp], esi
|
||
sub ecx, esi
|
||
jz .write_inode
|
||
|
||
.start_aligned:
|
||
cmp ecx, [ebp + EXTFS.block_size]
|
||
jb @F
|
||
|
||
mov eax, [esp]
|
||
xor edx, edx
|
||
div [ebp + EXTFS.block_size]
|
||
dec eax
|
||
|
||
call ext2_inode_free_entry
|
||
|
||
test eax, eax
|
||
jnz .error_inode_size
|
||
|
||
mov eax, [ebp + EXTFS.block_size]
|
||
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.block_size]
|
||
dec eax
|
||
|
||
push eax
|
||
call ext2_inode_read_entry
|
||
test eax, eax
|
||
pop eax
|
||
jnz .error_inode_size
|
||
|
||
mov edi, [ebp + EXTFS.ext2_save_block]
|
||
mov edx, [ebp + EXTFS.block_size]
|
||
sub edx, ecx
|
||
add edi, edx
|
||
|
||
push ecx eax
|
||
xor eax, eax
|
||
rep stosb
|
||
pop eax ecx
|
||
|
||
call ext2_inode_write_entry
|
||
test eax, eax
|
||
jnz .error_inode_size
|
||
|
||
sub [esp], ecx
|
||
|
||
.write_inode:
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
pop eax
|
||
mov [ebx + EXT2_INODE_STRUC.i_size], eax
|
||
mov eax, [esp]
|
||
call ext2_inode_write
|
||
|
||
test eax, eax
|
||
jnz .error
|
||
|
||
.success:
|
||
xor eax, eax
|
||
|
||
.ret:
|
||
add esp, 4
|
||
|
||
pop edi esi edx ecx ebx
|
||
ret
|
||
|
||
.error_inode_size:
|
||
mov ebx, [ebp + EXTFS.ext2_temp_inode]
|
||
pop eax
|
||
mov [ebx + EXT2_INODE_STRUC.i_size], eax
|
||
mov eax, [esp]
|
||
call ext2_inode_write
|
||
|
||
.error:
|
||
xor eax, eax
|
||
not eax
|
||
jmp .ret
|