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 |