Finished ext2 write support, under KSoC.

git-svn-id: svn://kolibrios.org@4066 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
shikhin 2013-10-21 09:30:07 +00:00
parent e3f61693b7
commit 7365b0cf3f
6 changed files with 3025 additions and 37 deletions

View File

@ -3953,7 +3953,7 @@ Format of the information structure:
* +0: dword: 2 = subfunction number * +0: dword: 2 = subfunction number
* +4: dword: 0 (reserved) * +4: dword: 0 (reserved)
* +8: 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 * +16 = +0x10: dword: pointer to data
* +20 = +0x14: ASCIIZ-name of file, the rules of names forming are * +20 = +0x14: ASCIIZ-name of file, the rules of names forming are
given in the general description given in the general description

View File

@ -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

View File

@ -8,9 +8,9 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include 'ext2.inc' include 'ext2.inc'
include 'blocks.asm' include 'blocks.inc'
include 'inode.asm' include 'inode.inc'
include 'resource.asm' include 'resource.inc'
iglobal iglobal
align 4 align 4
@ -197,6 +197,11 @@ proc ext2_create_partition
test eax, eax test eax, eax
jnz .error 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. mov eax, ebp ; Return pointer to EXTFS.
pop edi esi ebp ebx pop edi esi ebp ebx
ret ret
@ -252,6 +257,7 @@ endp
; eax = error code (0 implies no error) ; eax = error code (0 implies no error)
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
ext2_ReadFolder: ext2_ReadFolder:
;DEBUGF 1, "Reading folder.\n"
call ext2_lock call ext2_lock
cmp byte [esi], 0 cmp byte [esi], 0
jz .root_folder jz .root_folder
@ -306,7 +312,7 @@ ext2_ReadFolder:
add edx, 32 ; edx = mem to return. add edx, 32 ; edx = mem to return.
xor ecx, ecx ; Get number of first block. xor ecx, ecx ; Get number of first block.
call ext2_get_inode_block call ext2_inode_get_block
test eax, eax test eax, eax
jnz .error_get_block jnz .error_get_block
@ -355,7 +361,7 @@ ext2_ReadFolder:
; Read the next block. ; Read the next block.
push ecx push ecx
mov ecx, [edi] mov ecx, [edi]
call ext2_get_inode_block call ext2_inode_get_block
test eax, eax test eax, eax
jnz .error_get_block jnz .error_get_block
@ -482,6 +488,8 @@ ext2_ReadFolder:
lea edi, [edx + 12] lea edi, [edx + 12]
mov ecx, 20 / 4 mov ecx, 20 / 4
rep stosd rep stosd
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
.error_bad_len: .error_bad_len:
@ -497,7 +505,7 @@ ext2_ReadFolder:
push eax push eax
call ext2_unlock call ext2_unlock
pop eax pop eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
.error_empty_dir: ; inode of folder without blocks. .error_empty_dir: ; inode of folder without blocks.
@ -518,6 +526,7 @@ ext2_ReadFolder:
; eax = error code (0 implies no error) ; eax = error code (0 implies no error)
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
ext2_Read: ext2_Read:
;DEBUGF 1, "Attempting read.\n"
call ext2_lock call ext2_lock
cmp byte [esi], 0 cmp byte [esi], 0
jnz @F jnz @F
@ -607,7 +616,7 @@ ext2_Read:
push ecx push ecx
mov ecx, eax mov ecx, eax
call ext2_get_inode_block call ext2_inode_get_block
test eax, eax test eax, eax
jnz .error_at_first_block jnz .error_at_first_block
@ -651,7 +660,7 @@ ext2_Read:
inc dword [esp] inc dword [esp]
mov ecx, [esp] mov ecx, [esp]
call ext2_get_inode_block call ext2_inode_get_block
test eax, eax test eax, eax
jnz .error_at_read_cycle jnz .error_at_read_cycle
@ -674,7 +683,7 @@ ext2_Read:
pop ecx ; Pop block counter in ECX. pop ecx ; Pop block counter in ECX.
inc ecx inc ecx
call ext2_get_inode_block call ext2_inode_get_block
test eax, eax test eax, eax
jnz .error_at_finish_block jnz .error_at_finish_block
@ -705,6 +714,7 @@ ext2_Read:
ret ret
@@: @@:
xor eax, eax xor eax, eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
.only_one_block: .only_one_block:
@ -722,6 +732,8 @@ ext2_Read:
push eax push eax
call ext2_unlock call ext2_unlock
pop eax pop eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
@ -732,6 +744,7 @@ ext2_Read:
; Output: eax = error code. ; Output: eax = error code.
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
ext2_GetFileInfo: ext2_GetFileInfo:
;DEBUGF 1, "Calling for file info.\n"
call ext2_lock call ext2_lock
mov edx, [ebx + 16] mov edx, [ebx + 16]
cmp byte [esi], 0 cmp byte [esi], 0
@ -749,6 +762,8 @@ ext2_GetFileInfo:
push eax push eax
call ext2_unlock call ext2_unlock
pop eax pop eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
.is_root: .is_root:
@ -801,6 +816,7 @@ ext2_GetFileInfo:
call ext2_unlock call ext2_unlock
xor eax, eax xor eax, eax
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
@ -811,6 +827,13 @@ ext2_GetFileInfo:
; Output: eax = error code. ; Output: eax = error code.
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
ext2_SetFileInfo: ext2_SetFileInfo:
test [ebp + EXTFS.partition_flags], EXT2_RO
jz @F
mov eax, ERROR_UNSUPPORTED_FS
ret
@@:
push edx esi edi ebx push edx esi edi ebx
call ext2_lock call ext2_lock
mov edx, [ebx + 16] mov edx, [ebx + 16]
@ -888,6 +911,14 @@ ext2_SetFileInfo:
; Output: eax = error code. ; Output: eax = error code.
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
ext2_Delete: 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 push ebx ecx edx esi edi
call ext2_lock call ext2_lock
@ -971,7 +1002,7 @@ ext2_Delete:
@@: @@:
push ecx push ecx
call ext2_get_inode_block call ext2_inode_get_block
test eax, eax test eax, eax
jnz .error_stack8 jnz .error_stack8
mov eax, ecx mov eax, ecx
@ -989,6 +1020,11 @@ ext2_Delete:
jmp @B jmp @B
@@: @@:
; Free indirect blocks.
call ext2_inode_free_indirect_blocks
test eax, eax
jnz .error_stack4
; Clear the inode, and add deletion time. ; Clear the inode, and add deletion time.
mov edi, [ebp + EXTFS.ext2_save_inode] mov edi, [ebp + EXTFS.ext2_save_inode]
xor eax, eax xor eax, eax
@ -1047,6 +1083,7 @@ ext2_Delete:
pop eax pop eax
pop edi esi edx ecx ebx pop edi esi edx ecx ebx
;DEBUGF 1, "And returning with: %x.\n", eax
ret ret
.error_stack8: .error_stack8:
@ -1071,12 +1108,20 @@ ext2_Delete:
; Output: eax = error code. ; Output: eax = error code.
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
ext2_CreateFolder: 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 push ebx ecx edx esi edi
call ext2_lock call ext2_lock
add esi, [esp + 20 + 4] 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 cmp byte [esi], 0
jz .success jz .success
@ -1194,6 +1239,7 @@ ext2_CreateFolder:
pop eax pop eax
pop edi esi edx ecx ebx pop edi esi edx ecx ebx
;DEBUGF 1, "Returning with: %x.\n", eax
ret ret
.error: .error:
@ -1210,12 +1256,464 @@ ext2_CreateFolder:
mov eax, ERROR_DISK_FULL mov eax, ERROR_DISK_FULL
jmp .return jmp .return
self_link: db ".", 0 self_link db ".", 0
parent_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: ext2_Rewrite:
ext2_Write: ;DEBUGF 1, "Attempting Rewrite.\n"
ext2_SetFileEnd: test [ebp + EXTFS.partition_flags], EXT2_RO
xor ebx, ebx jz @F
mov eax, ERROR_UNSUPPORTED_FS mov eax, ERROR_UNSUPPORTED_FS
ret 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:
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

View File

@ -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). ; Recommended move to some kernel-wide bitmap handling code (with a bit of abstraction, of course).
;--------------------------------------------------------------------- ;---------------------------------------------------------------------
@ -86,6 +93,7 @@ bitmap_find_free_bit:
; We found the value. Let's return with it. ; We found the value. Let's return with it.
add esp, 4 add esp, 4
add eax, edx add eax, edx
jmp .return jmp .return

File diff suppressed because it is too large Load Diff

View File

@ -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