Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 4056 → Rev 4066

/kernel/trunk/docs/sysfuncs.txt
3953,7 → 3953,7
* +0: dword: 2 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: number of bytes to read
* +12 = +0xC: dword: number of bytes to write
* +16 = +0x10: dword: pointer to data
* +20 = +0x14: ASCIIZ-name of file, the rules of names forming are
given in the general description
/kernel/trunk/fs/ext2/blocks.inc
0,0 → 1,409
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Contains ext2 block handling code. ;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under the terms of the new BSD license. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;---------------------------------------------------------------------
; Write ext2 block from memory to disk.
; Input: eax = i_block (block number in ext2 terms);
; ebx = buffer address
; ebp = pointer to EXTFS
; Output: eax = error code (0 implies no error)
;---------------------------------------------------------------------
ext2_block_write:
push edx ebx ecx
 
mov edx, fs_write32_sys
jmp ext2_block_modify
 
;---------------------------------------------------------------------
; Read ext2 block from disk to memory.
; Input: eax = i_block (block number in ext2 terms);
; ebx = address of where to read block
; ebp = pointer to EXTFS
; Output: eax = error code (0 implies no error)
;---------------------------------------------------------------------
ext2_block_read:
push edx ebx ecx
mov edx, fs_read32_sys
jmp ext2_block_modify
 
;---------------------------------------------------------------------
; Modify ext2 block.
; Input: eax = i_block (block number in ext2 terms);
; ebx = I/O buffer address;
; edx = fs_read/write32_sys
; ebp = pointer to EXTFS
; edx, ebx, ecx on stack.
; Output: eax = error code (0 implies no error)
;---------------------------------------------------------------------
ext2_block_modify:
; Get block number in hard-disk terms in eax.
mov ecx, [ebp + EXTFS.log_block_size]
shl eax, cl
mov ecx, eax
push [ebp + EXTFS.count_block_in_block]
 
@@:
mov eax, ecx
call edx
test eax, eax
jnz .fail
inc ecx
add ebx, 512
dec dword[esp]
jnz @B
 
xor eax, eax
@@:
pop ecx
pop ecx ebx edx
ret
 
.fail:
mov eax, ERROR_DEVICE
jmp @B
 
;---------------------------------------------------------------------
; Zeroes a block.
; Input: ebx = block ID.
; ebp = pointer to EXTFS.
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_block_zero:
push ebx
 
mov eax, ebx
mov ebx, [ebp + EXTFS.ext2_temp_block]
 
call ext2_block_read
test eax, eax
jnz .return
 
push edi ecx
xor eax, eax
mov ecx, [ebp + EXTFS.block_size]
mov edi, [ebp + EXTFS.ext2_temp_block]
rep stosb
pop ecx edi
 
mov eax, [esp]
call ext2_block_write
 
.return:
pop ebx
ret
 
;---------------------------------------------------------------------
; Allocates a block.
; Input: eax = inode ID for "preference".
; ebp = pointer to EXTFS.
; Output: Block marked as set in block group.
; eax = error code.
; ebx = block ID.
;---------------------------------------------------------------------
ext2_block_alloc:
push [ebp + EXTFS.superblock + EXT2_SB_STRUC.blocks_count]
push EXT2_BLOCK_GROUP_DESC.free_blocks_count
push [ebp + EXTFS.superblock + EXT2_SB_STRUC.blocks_per_group]
 
lea ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_block_count]
push ebx
 
push ext2_bg_read_blk_bitmap
 
call ext2_resource_alloc
 
ret
 
;---------------------------------------------------------------------
; Zero-allocates a block.
; Input: eax = inode ID for "preference".
; ebp = pointer to EXTFS.
; Output: Block marked as set in block group.
; eax = error code.
; ebx = block ID.
;---------------------------------------------------------------------
ext2_block_calloc:
call ext2_block_alloc
test eax, eax
jnz @F
 
call ext2_block_zero
@@:
ret
 
;---------------------------------------------------------------------
; Frees a block.
; Input: eax = block ID.
; ebp = pointer to EXTFS.
; Output: Block marked as free in block group.
; eax = error code.
;---------------------------------------------------------------------
ext2_block_free:
push edi ecx
 
mov edi, ext2_bg_read_blk_bitmap
xor ecx, ecx
call ext2_resource_free
 
pop ecx edi
ret
 
;---------------------------------------------------------------------
; Find parent from file path in block.
; Input: esi = file path.
; ebx = pointer to directory block.
; ebp = pointer to EXTFS structure.
; Output: esi = name without parent, or not changed.
; ebx = directory record matched.
;---------------------------------------------------------------------
ext2_block_find_parent:
sub esp, 256 ; Space for EXT2 filename.
mov edx, ebx
add edx, [ebp + EXTFS.block_size] ; Save block end.
 
.start_rec:
cmp [ebx + EXT2_DIR_STRUC.inode], 0
jz .next_rec
 
mov edi, esp
push esi
movzx ecx, [ebx + EXT2_DIR_STRUC.name_len]
lea esi, [ebx + EXT2_DIR_STRUC.name]
call utf8_to_cp866
 
mov ecx, edi
lea edi, [esp + 4]
sub ecx, edi ; Number of bytes in resulting string.
 
mov esi, [esp]
 
; esi: original file path.
; edi: converted string stored on stack.
; ecx: size of converted string.
@@:
; If no bytes left in resulting string, test it.
jecxz .test_find
dec ecx
 
lodsb
call char_toupper
 
mov ah, [edi]
inc edi
xchg al, ah
call char_toupper
 
; If both are same, check next byte.
cmp al, ah
je @B
@@: ; Doesn't match.
pop esi
.next_rec:
movzx eax, [ebx + EXT2_DIR_STRUC.rec_len]
add ebx, eax ; Go to next record.
cmp ebx, edx ; Check if this is the end.
jb .start_rec
add esp, 256
ret
 
.test_find:
cmp byte [esi], 0
je .ret ; The end reached.
cmp byte [esi], '/' ; If not end of directory name, not matched.
jne @B
inc esi
 
.ret:
add esp, 256 + 4
ret
 
;---------------------------------------------------------------------
; Finds free space in a directory block, modifying last entry appropriately.
; Input: ebp = pointer to EXTFS.
; ecx = size of free space required.
; [EXTFS.ext2_temp_block] contains the block relevant.
; Output: edi = free entry.
; rec_len of free entry is set.
; eax = error code; if the block doesn't link to the next one, this is 0x00000001 on failure.
; ; else, 0xFFFFFFFF.
;---------------------------------------------------------------------
ext2_block_find_fspace:
push ebx edx
 
mov edi, [ebp + EXTFS.ext2_temp_block]
mov edx, edi
add edx, [ebp + EXTFS.block_size]
 
@@:
movzx eax, [edi + EXT2_DIR_STRUC.rec_len]
test eax, eax
jz .zero_len
 
cmp [edi + EXT2_DIR_STRUC.inode], 0
je .unused_entry
 
; It's a used entry, so see if we can fit it between current one and next.
; Subtract the size used by the name and the structure from rec_len.
movzx ebx, [edi + EXT2_DIR_STRUC.name_len]
add ebx, 8 + 3
and ebx, 0xfffffffc ; Align it on the next 4-byte boundary.
 
sub eax, ebx
add edi, ebx
cmp eax, ecx
jb .next_iter
 
sub edi, ebx
mov [edi + EXT2_DIR_STRUC.rec_len], bx ; Make previous entry point to us.
add edi, ebx
 
mov [edi + EXT2_DIR_STRUC.rec_len], ax ; Make current entry point to next one.
jmp .found
 
.unused_entry:
; It's an unused inode.
cmp eax, ecx
jge .found
 
.next_iter:
add edi, eax
cmp edi, edx
jb @B
 
.not_found:
xor eax, eax
not eax
jmp .ret
 
; Zero length entry means we have the rest of the block for us.
.zero_len:
mov eax, edx
sub eax, edi
 
; Point to next block.
mov [edi + EXT2_DIR_STRUC.rec_len], ax
 
cmp eax, ecx
jge .fits
 
mov [edi + EXT2_DIR_STRUC.inode], 0
 
; It doesn't fit, but the block doesn't link to the next block.
xor eax, eax
inc eax
jmp .ret
 
.fits:
mov [edi + EXT2_DIR_STRUC.rec_len], cx
 
.found:
xor eax, eax
 
.ret:
pop edx ebx
ret
 
;---------------------------------------------------------------------
; Gets the block group's descriptor.
; Input: eax = block group.
; Output: eax = if zero, error; else, points to block group descriptor.
; [EXTFS.ext2_temp_block] contains relevant block.
; ebp = pointer to EXTFS.
;---------------------------------------------------------------------
ext2_bg_read_desc:
push edx ebx
mov edx, 32
mul edx ; Get index of descriptor in global_desc_table.
 
; eax: block group descriptor 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 .fail
 
add ebx, edx ; edx: local index of descriptor inside block
mov eax, ebx
 
.return:
pop ebx edx
ret
 
.fail:
xor eax, eax
jmp .return
 
;---------------------------------------------------------------------
; Writes a block group's descriptor.
; Input: eax = block group.
; [EXTFS.ext2_temp_data] contains the block relevant.
; ebp = pointer to EXTFS.
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_bg_write_desc:
push edx ebx
mov edx, 32
mul edx ; Get index of descriptor in global_desc_table.
 
; eax: block group descriptor 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_write
 
.return:
pop ebx edx
ret
 
;---------------------------------------------------------------------
; Gets the block group's block bitmap.
; Input: eax = block group.
; Output: eax = if zero, error; else, points to block group descriptor.
; ebx = block bitmap's block (hard disk).
;---------------------------------------------------------------------
ext2_bg_read_blk_bitmap:
push ecx
 
call ext2_bg_read_desc
test eax, eax
jz .fail
 
mov ebx, [eax + EXT2_BLOCK_GROUP_DESC.block_bitmap] ; Block number of block group bitmap - in ext2 terms.
 
.return:
pop ecx
ret
 
.fail:
xor eax, eax
jmp .return
 
;---------------------------------------------------------------------
; Updates superblock, plus backups.
; Input: ebp = pointer to EXTFS.
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_sb_update:
push ebx
 
mov eax, 2
lea ebx, [ebp + EXTFS.superblock]
call fs_write32_sys
 
pop ebx
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/trunk/fs/ext2/ext2.asm
8,9 → 8,9
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
include 'ext2.inc'
include 'blocks.asm'
include 'inode.asm'
include 'resource.asm'
include 'blocks.inc'
include 'inode.inc'
include 'resource.inc'
 
iglobal
align 4
197,6 → 197,11
test eax, eax
jnz .error
 
;call ext2_sb_update
; Sync the disk.
;mov esi, [ebp + PARTITION.Disk]
;call disk_sync ; eax contains error code, if any.
 
mov eax, ebp ; Return pointer to EXTFS.
pop edi esi ebp ebx
ret
252,6 → 257,7
; eax = error code (0 implies no error)
;---------------------------------------------------------------------
ext2_ReadFolder:
;DEBUGF 1, "Reading folder.\n"
call ext2_lock
cmp byte [esi], 0
jz .root_folder
306,7 → 312,7
add edx, 32 ; edx = mem to return.
 
xor ecx, ecx ; Get number of first block.
call ext2_get_inode_block
call ext2_inode_get_block
test eax, eax
jnz .error_get_block
 
355,7 → 361,7
; Read the next block.
push ecx
mov ecx, [edi]
call ext2_get_inode_block
call ext2_inode_get_block
test eax, eax
jnz .error_get_block
 
482,6 → 488,8
lea edi, [edx + 12]
mov ecx, 20 / 4
rep stosd
 
;DEBUGF 1, "Returning with: %x.\n", eax
ret
 
.error_bad_len:
497,7 → 505,7
push eax
call ext2_unlock
pop eax
 
;DEBUGF 1, "Returning with: %x.\n", eax
ret
.error_empty_dir: ; inode of folder without blocks.
518,6 → 526,7
; eax = error code (0 implies no error)
;---------------------------------------------------------------------
ext2_Read:
;DEBUGF 1, "Attempting read.\n"
call ext2_lock
cmp byte [esi], 0
jnz @F
607,7 → 616,7
push ecx
mov ecx, eax
call ext2_get_inode_block
call ext2_inode_get_block
test eax, eax
jnz .error_at_first_block
 
651,7 → 660,7
inc dword [esp]
mov ecx, [esp]
call ext2_get_inode_block
call ext2_inode_get_block
 
test eax, eax
jnz .error_at_read_cycle
674,7 → 683,7
 
pop ecx ; Pop block counter in ECX.
inc ecx
call ext2_get_inode_block
call ext2_inode_get_block
test eax, eax
jnz .error_at_finish_block
705,6 → 714,7
ret
@@:
xor eax, eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret
.only_one_block:
722,6 → 732,8
push eax
call ext2_unlock
pop eax
 
;DEBUGF 1, "Returning with: %x.\n", eax
ret
 
;---------------------------------------------------------------------
732,6 → 744,7
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_GetFileInfo:
;DEBUGF 1, "Calling for file info.\n"
call ext2_lock
mov edx, [ebx + 16]
cmp byte [esi], 0
749,6 → 762,8
push eax
call ext2_unlock
pop eax
 
;DEBUGF 1, "Returning with: %x.\n", eax
ret
 
.is_root:
801,6 → 816,7
 
call ext2_unlock
xor eax, eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret
 
;---------------------------------------------------------------------
811,6 → 827,13
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_SetFileInfo:
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
 
mov eax, ERROR_UNSUPPORTED_FS
ret
 
@@:
push edx esi edi ebx
call ext2_lock
mov edx, [ebx + 16]
888,6 → 911,14
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_Delete:
;DEBUGF 1, "Attempting Delete.\n"
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
 
mov eax, ERROR_UNSUPPORTED_FS
ret
@@:
push ebx ecx edx esi edi
call ext2_lock
 
971,7 → 1002,7
 
@@:
push ecx
call ext2_get_inode_block
call ext2_inode_get_block
test eax, eax
jnz .error_stack8
mov eax, ecx
989,6 → 1020,11
jmp @B
 
@@:
; Free indirect blocks.
call ext2_inode_free_indirect_blocks
test eax, eax
jnz .error_stack4
 
; Clear the inode, and add deletion time.
mov edi, [ebp + EXTFS.ext2_save_inode]
xor eax, eax
1047,6 → 1083,7
pop eax
 
pop edi esi edx ecx ebx
;DEBUGF 1, "And returning with: %x.\n", eax
ret
 
.error_stack8:
1071,12 → 1108,20
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_CreateFolder:
;DEBUGF 1, "Attempting to create folder.\n"
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
 
mov eax, ERROR_UNSUPPORTED_FS
ret
@@:
push ebx ecx edx esi edi
call ext2_lock
 
add esi, [esp + 20 + 4]
 
; Can't create root, but for CreateFile already existing directory is success.
; Can't create root, but for CreateFolder already existing directory is success.
cmp byte [esi], 0
jz .success
 
1194,6 → 1239,7
pop eax
 
pop edi esi edx ecx ebx
;DEBUGF 1, "Returning with: %x.\n", eax
ret
 
.error:
1210,12 → 1256,464
mov eax, ERROR_DISK_FULL
jmp .return
 
self_link: db ".", 0
parent_link: db "..", 0
self_link db ".", 0
parent_link db "..", 0
 
;---------------------------------------------------------------------
; Rewrite a file.
; Input: esi + [esp + 4] = file name.
; ebx = pointer to paramteres from sysfunc 70.
; ebp = pointer to EXTFS structure.
; Output: eax = error code.
; ebx = bytes written.
;---------------------------------------------------------------------
ext2_Rewrite:
;DEBUGF 1, "Attempting Rewrite.\n"
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
 
mov eax, ERROR_UNSUPPORTED_FS
ret
@@:
push ecx edx esi edi
pushad
 
call ext2_lock
 
add esi, [esp + 16 + 32 + 4]
; Can't create root.
cmp byte [esi], 0
jz .error_access_denied
 
push esi
stdcall ext2_inode_find, 0
pop esi
 
; If the file is there, delete it.
test eax, eax
jnz @F
 
pushad
 
push eax
call ext2_unlock
pop eax
 
push dword 0x00000000
call ext2_Delete
add esp, 4
 
push eax
call ext2_lock
pop eax
 
test eax, eax
jnz .error_access_denied_delete
 
popad
@@:
; Find parent.
call ext2_inode_find_parent
test eax, eax
jnz .error_access_denied
 
; Inode ID for preference.
mov eax, esi
call ext2_inode_alloc
test eax, eax
jnz .error_full
 
; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
mov edx, ebx
 
push edi
 
xor al, al
mov edi, [ebp + EXTFS.ext2_temp_inode]
mov ecx, [ebp + EXTFS.inode_size]
rep stosb
 
mov edi, [ebp + EXTFS.ext2_temp_inode]
add edi, EXT2_INODE_STRUC.i_atime
call current_unix_time
 
add edi, 8
call current_unix_time
 
pop edi
 
mov ebx, [ebp + EXTFS.ext2_temp_inode]
mov [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
mov eax, edx
call ext2_inode_write
test eax, eax
jnz .error
 
; Link parent to child.
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, EXT2_FT_REG_FILE
call ext2_inode_link
test eax, eax
jnz .error
 
popad
push eax
call ext2_unlock
pop eax
 
push dword 0x00000000
call ext2_Write
add esp, 4
 
push eax
call ext2_lock
pop eax
 
.success:
push eax
call ext2_sb_update
 
; Sync the disk.
mov esi, [ebp + PARTITION.Disk]
call disk_sync ; eax contains error code, if any.
pop eax
 
.return:
push eax
call ext2_unlock
pop eax
 
pop edi esi edx ecx
 
;DEBUGF 1, "And returning with: %x.\n", eax
ret
 
.error:
mov eax, ERROR_ACCESS_DENIED
jmp .success
 
.error_access_denied_delete:
popad
 
.error_access_denied:
popad
xor ebx, ebx
 
mov eax, ERROR_ACCESS_DENIED
jmp .return
 
.error_full:
popad
xor ebx, ebx
 
mov eax, ERROR_DISK_FULL
jmp .return
 
;---------------------------------------------------------------------
; Write to a file.
; Input: esi + [esp + 4] = file name.
; ebx = pointer to paramteres from sysfunc 70.
; ebp = pointer to EXTFS structure.
; Output: eax = error code.
; ebx = number of bytes written.
;---------------------------------------------------------------------
ext2_Write:
;DEBUGF 1, "Attempting write, "
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
 
mov eax, ERROR_UNSUPPORTED_FS
ret
@@:
push ecx edx esi edi
call ext2_lock
 
add esi, [esp + 16 + 4]
 
; Can't write to root.
cmp byte [esi], 0
jz .error
 
push ebx ecx edx
stdcall ext2_inode_find, 0
pop edx ecx ebx
; If file not there, error.
xor ecx, ecx
test eax, eax
jnz .error_file_not_found
 
; Save the inode.
push esi
 
; Check if it's a file.
mov edx, [ebp + EXTFS.ext2_save_inode]
cmp [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
jne .error
 
mov eax, esi
mov ecx, [ebx + 4]
 
call ext2_inode_extend
xor ecx, ecx
test eax, eax
jnz .error_device
 
; ECX contains the size to write, and ESI points to it.
mov ecx, [ebx + 0x0C]
mov esi, [ebx + 0x10]
 
; Save the size of the inode.
mov eax, [edx + EXT2_INODE_STRUC.i_size]
push 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 ebx, [ebp + EXTFS.block_size]
sub ebx, edx
 
cmp ebx, ecx
jbe @F
 
; If the size to copy fits in current block, limit to that, instead of the entire block.
mov ebx, ecx
 
@@:
; Copy EBX bytes, in EAX indexed block.
push eax
call ext2_inode_read_entry
test eax, eax
pop eax
jnz .error_inode_size
 
push ecx
mov ecx, ebx
mov edi, ebx
add edi, edx
rep movsb
 
pop ecx
 
; Write the block.
call ext2_inode_write_entry
test eax, eax
jnz .error_inode_size
 
add [esp], ebx
sub ecx, ebx
jz .write_inode
 
.start_aligned:
cmp ecx, [ebp + EXTFS.block_size]
jb @F
 
mov eax, [esp]
xor edx, edx
div [ebp + EXTFS.block_size]
 
push eax
mov edx, [esp + 8]
call ext2_inode_blank_entry
test eax, eax
pop eax
jnz .error_inode_size
 
push ecx
 
mov ecx, [ebp + EXTFS.block_size]
mov edi, [ebp + EXTFS.ext2_save_block]
rep movsb
 
pop ecx
 
call ext2_inode_write_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]
 
push eax
call ext2_inode_read_entry
test eax, eax
pop eax
jz @F
 
push eax
mov edx, [esp + 8]
 
call ext2_inode_blank_entry
test eax, eax
pop eax
jnz .error_inode_size
 
@@:
push ecx
mov edi, [ebp + EXTFS.ext2_save_block]
rep movsb
pop ecx
 
call ext2_inode_write_entry
test eax, eax
jnz .error_inode_size
 
add [esp], ecx
xor ecx, 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_device
 
.success:
call ext2_sb_update
 
; Sync the disk.
mov esi, [ebp + PARTITION.Disk]
call disk_sync ; eax contains error code, if any.
 
.return:
push eax
call ext2_unlock
pop eax
 
add esp, 4
 
mov ebx, [esp + 12]
sub ebx, ecx
pop edi esi edx ecx
 
;DEBUGF 1, "and returning with: %x.\n", eax
ret
 
.error:
mov eax, ERROR_ACCESS_DENIED
jmp .return
 
.error_file_not_found:
mov eax, ERROR_FILE_NOT_FOUND
jmp .return
 
.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_device:
call ext2_sb_update
 
; Sync the disk.
mov esi, [ebp + PARTITION.Disk]
call disk_sync ; eax contains error code, if any.
 
mov eax, ERROR_DEVICE
jmp .return
 
;---------------------------------------------------------------------
; Set the end of a file.
; Input: esi + [esp + 4] = file name.
; ebx = pointer to paramteres from sysfunc 70.
; ebp = pointer to EXTFS structure.
; Output: eax = error code.
;---------------------------------------------------------------------
ext2_SetFileEnd:
xor ebx, ebx
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
 
mov eax, ERROR_UNSUPPORTED_FS
ret
@@:
push ebx ecx edx esi edi
call ext2_lock
 
add esi, [esp + 20 + 4]
 
; Can't write to root.
cmp byte [esi], 0
jz .error
 
stdcall ext2_inode_find, 0
; If file not there, error.
test eax, eax
jnz .error_file_not_found
 
; Check if it's a file.
mov edx, [ebp + EXTFS.ext2_save_inode]
cmp [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
jne .error
 
mov eax, esi
mov ecx, [ebx + 4]
call ext2_inode_extend
test eax, eax
jnz .error_disk_full
 
mov eax, esi
call ext2_inode_truncate
test eax, eax
jnz .error_disk_full
 
mov eax, esi
mov ebx, [ebp + EXTFS.ext2_temp_inode]
call ext2_inode_write
 
call ext2_sb_update
 
; Sync the disk.
mov esi, [ebp + PARTITION.Disk]
call disk_sync ; eax contains error code, if any.
 
.return:
push eax
call ext2_unlock
pop eax
 
pop edi esi edx ecx ebx
ret
 
.error:
mov eax, ERROR_ACCESS_DENIED
jmp .return
 
.error_file_not_found:
mov eax, ERROR_FILE_NOT_FOUND
jmp .return
 
.error_disk_full:
call ext2_sb_update
 
; Sync the disk.
mov esi, [ebp + PARTITION.Disk]
call disk_sync ; eax contains error code, if any.
 
mov eax, ERROR_DISK_FULL
jmp .return
/kernel/trunk/fs/ext2/ext2.inc
7,6 → 7,13
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; Future jobs for driver, in order of preference:
; * clean up existing extents support.
; * add b-tree directories support.
; * add long file support.
; * add journal support.
; * add minor features that come with ext3/4.
 
; Recommended move to some kernel-wide bitmap handling code (with a bit of abstraction, of course).
 
;---------------------------------------------------------------------
86,6 → 93,7
 
; We found the value. Let's return with it.
add esp, 4
 
add eax, edx
jmp .return
/kernel/trunk/fs/ext2/inode.inc
0,0 → 1,1850
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Contains ext2 inode handling code. ;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under the terms of the new BSD license. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;---------------------------------------------------------------------
; 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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/trunk/fs/ext2/resource.inc
0,0 → 1,223
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Contains common resource allocation + freeing code. ;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under the terms of the new BSD license. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;---------------------------------------------------------------------
; Frees a resource (block/inode).
; Input: eax = resource ID.
; edi = function pointer of ext2_bg_*_bitmap form, to
; get bitmap of resource.
; ecx = 0, block; 1, inode.
; ebp = pointer to EXTFS.
; Output: Block marked as free in block group.
; eax = error code.
;---------------------------------------------------------------------
ext2_resource_free:
push ebx edx esi
 
; Get block group.
sub eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block]
xor edx, edx
div [ebp + EXTFS.superblock + EXT2_SB_STRUC.blocks_per_group]
push eax edx
 
call edi
test eax, eax
jz .fail
mov esi, eax
 
; Read the bitmap.
mov eax, ebx
mov edx, eax
mov ebx, [ebp + EXTFS.ext2_save_block]
call ext2_block_read
test eax, eax
jnz .fail
 
pop eax
; Mark bit free.
call bitmap_clear_bit
test eax, eax
jz @F
 
; No need to save anything.
xor eax, eax
 
add esp, 4
jmp .return
 
@@:
mov eax, edx
mov ebx, [ebp + EXTFS.ext2_save_block]
call ext2_block_write
test eax, eax
jnz .fail
 
; Read the descriptor.
mov eax, [esp]
call ext2_bg_read_desc
test eax, eax
jz .fail_bg_desc_read
 
lea eax, [eax + EXT2_BLOCK_GROUP_DESC.free_blocks_count]
shl ecx, 1
add eax, ecx
inc word[eax]
 
lea eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_block_count]
shl ecx, 1
add eax, ecx
inc dword[eax]
 
pop eax
call ext2_bg_write_desc
 
.return:
pop esi edx ebx
ret
 
.fail:
add esp, 4
.fail_bg_desc_read:
add esp, 4
xor eax, eax
not eax
jmp .return
 
;---------------------------------------------------------------------
; Allocates a resource.
; Input: eax = inode ID for "preference".
; ebp = pointer to EXTFS.
; [esp + 4], func pointer to ext2_bg_*_bitmap
; [esp + 8], pointer to free_*_count in SB.
; [esp + 12], *_per_group
; [esp + 16], offset to free_*_count in bg descriptor.
; [esp + 20], *_count
; Output: Resource marked as set in block group.
; eax = error code.
; ebx = resource ID.
;---------------------------------------------------------------------
ext2_resource_alloc:
; Block allocation is a pretty serious area, since bad allocation
; can lead to fragmentation. Thus, the best way to allocate that
; comes to mind is to allocate around an inode as much as possible.
; On the other hand, this isn't about a single inode/file/directory,
; and focusing just around the preferred inode would lead to
; congestion. Thus, after much thought, the chosen allocation algorithm
; is to search forward, then backward.
push ecx edx esi edi
 
cmp dword[esp + 16 + 8], 0
jnz @F
 
; No free blocks.
xor eax, eax
not eax
pop edi esi edx ecx
ret 20
 
@@:
; Calculate which block group the preferred inode belongs to.
dec eax
xor edx, edx
; EAX = block group.
div [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
push eax
push eax
 
mov edi, .forward
 
.test_block_group:
call dword[esp + 16 + 8 + 4]
test eax, eax
jz .fail
mov esi, eax
 
mov eax, ebx
mov edx, eax
mov ebx, [ebp + EXTFS.ext2_save_block]
call ext2_block_read
test eax, eax
jnz .fail
 
mov ecx, [esp + 16 + 8 + 12]
call ext2_find_free_bit
cmp eax, 0xFFFFFFFF
jne @F
 
mov eax, edi
jmp eax
 
@@:
mov ecx, eax
 
mov eax, edx
mov ebx, [ebp + EXTFS.ext2_save_block]
call ext2_block_write
test eax, eax
jnz .fail
 
; ecx: the index of the matched entry.
; [esp]: block group where we found.
; [esp + 4]: starting block group.
; esi: block group descriptor.
mov eax, [esp] ; Index of block group in which we found.
mul dword[esp + 16 + 8 + 12]
add eax, ecx
mov ebx, eax
 
mov eax, [esp + 16 + 8 + 8]
dec dword[eax]
 
mov eax, esi
add eax, [esp + 16 + 8 + 16]
dec word[eax]
 
pop eax
call ext2_bg_write_desc
 
add esp, 4
jmp .return
 
; Continue forward.
.forward:
inc dword[esp]
mov eax, [esp]
mul dword[esp + 16 + 8 + 12]
cmp eax, [esp + 16 + 8 + 20]
jbe @F
 
; We need to go backward.
mov eax, [esp + 4]
mov [esp], eax
mov edi, .backward
jmp .backward
 
@@:
mov eax, [esp]
jmp .test_block_group
 
; Continue backward.
.backward:
cmp dword[esp], 0
je .fail
 
dec dword[esp]
mov eax, [esp]
jmp .test_block_group
 
.return:
pop edi esi edx ecx
ret 20
 
.fail:
add esp, 8
xor eax, eax
not eax
jmp .return
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property