kolibrios-fun/kernel/branches/Kolibri-acpi/fs/ext2.inc
Sergey Semyonov (Serge) 8423f9ffb6 acpi:merge trunk
git-svn-id: svn://kolibrios.org@3908 a494cfbc-eb01-0410-851d-a64ba20cac60
2013-09-14 18:55:13 +00:00

1344 lines
51 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; 02.02.2010 turbanoff - support 70.5 ;;
;; 23.01.2010 turbanoff - support 70.0 70.1 ;;
;; 21.06.2013 yogev_ezra - Translate Russian comments ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
EXT2_BAD_INO = 1
EXT2_ROOT_INO = 2
EXT2_ACL_IDX_INO = 3
EXT2_ACL_DATA_INO = 4
EXT2_BOOT_LOADER_INO = 5
EXT2_UNDEL_DIR_INO = 6
;RUS: флаги, указываемые в inode файла ;ENG: flags specified in file inode
EXT2_S_IFREG = 0x8000
EXT2_S_IFDIR = 0x4000
EXT2_S_IFMT = 0xF000 ;RUS: маска для типа файла ;ENG: mask for file type
;RUS: флаги, указываемые в linked list родительской папки
;ENG: flags specified in linked list of parent folder
EXT2_FT_REG_FILE = 1 ;RUS: это файл, запись в родительском каталоге
;ENG: this is a file, record in parent catalog
EXT2_FT_DIR = 2 ;RUS: это папка ;ENG: this is a folder
;RUS: флаги используемые KolibriOS ;ENG: flags used by KolibriOS
FS_FT_HIDDEN = 2
FS_FT_DIR = 0x10 ;RUS: это папка ;ENG: this is a folder
FS_FT_ASCII = 0 ;RUS: имя в ascii ;ENG: name in ASCII
FS_FT_UNICODE = 1 ;RUS: имя в unicode ;ENG: name in UNICODE
EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002 ;RUS: тип файла должен указываться в директории
;ENG: file type must be specified in the folder
EXT4_FEATURE_INCOMPAT_EXTENTS = 0x0040 ;RUS: экстенты ;ENG: extents
EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x0200 ;RUS: гибкие группы блоков ;ENG: flexible block groups
;RUS: реализованные ext[234] features ;ENG: implemented ext[234] features
EXT4_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE \
or EXT4_FEATURE_INCOMPAT_EXTENTS \
or EXT4_FEATURE_INCOMPAT_FLEX_BG
;RUS: флаги, указываемые для inode в i_flags ;ENG: flags specified for inode in i_flags
EXT2_EXTENTS_FL = 0x00080000
struct EXT2_INODE_STRUC
i_mode dw ?
i_uid dw ?
i_size dd ?
i_atime dd ?
i_ctime dd ?
i_mtime dd ?
i_dtime dd ?
i_gid dw ?
i_links_count dw ?
i_blocks dd ?
i_flags dd ?
i_osd1 dd ?
i_block rd 15
i_generation dd ?
i_file_acl dd ?
i_dir_acl dd ?
i_faddr dd ?
i_osd2 dd ? ; 1..12
ends
struct EXT2_DIR_STRUC
inode dd ?
rec_len dw ?
name_len db ?
file_type db ?
name db ? ; 0..255
ends
struct EXT2_BLOCK_GROUP_DESC
block_bitmap dd ? ;+0
inode_bitmap dd ? ;+4
inode_table dd ? ;+8
free_blocks_count dw ? ;+12
free_inodes_count dw ? ;+14
used_dirs_count dw ? ;+16
pad dw ? ;+18
reserved rb 12;+20
ends
struct EXT2_SB_STRUC
inodes_count dd ? ;+0
blocks_count dd ? ;+4
r_block_count dd ? ;+8
free_block_count dd ? ;+12
free_inodes_count dd ? ;+16
first_data_block dd ? ;+20
log_block_size dd ? ;+24
log_frag_size dd ? ;+28
blocks_per_group dd ? ;+32
frags_per_group dd ? ;+36
inodes_per_group dd ? ;+40
mtime dd ? ;+44
wtime dd ? ;+48
mnt_count dw ? ;+52
max_mnt_count dw ? ;+54
magic dw ? ;+56
state dw ? ;+58
errors dw ? ;+60
minor_rev_level dw ? ;+62
lastcheck dd ? ;+64
check_intervals dd ? ;+68
creator_os dd ? ;+72
rev_level dd ? ;+76
def_resuid dw ? ;+80
def_resgid dw ? ;+82
first_ino dd ? ;+84
inode_size dw ? ;+88
block_group_nr dw ? ;+90
feature_compat dd ? ;+92
feature_incompat dd ? ;+96
feature_ro_compat dd ? ;+100
uuid rb 16 ;+104
volume_name rb 16 ;+120
last_mounted rb 64 ;+136
algo_bitmap dd ? ;+200
prealloc_blocks db ? ;+204
preallock_dir_blocks db ? ;+205
reserved_gdt_blocks dw ? ;+206
journal_uuid rb 16 ;+208
journal_inum dd ? ;+224
journal_dev dd ? ;+228
last_orphan dd ? ;+232
hash_seed rd 4 ;+236
def_hash_version db ? ;+252
rb 3 ;+253 reserved
default_mount_options dd ? ;+256
first_meta_bg dd ? ;+260
mkfs_time dd ? ;+264
jnl_blocks rd 17 ;+268
blocks_count_hi dd ? ;+336
r_blocks_count_hi dd ? ;+340
free_blocks_count_hi dd ? ;+344
min_extra_isize dw ? ;+348
want_extra_isize dw ? ;+350
flags dd ? ;+352
raid_stride dw ? ;+356
mmp_interval dw ? ;+358
mmp_block dq ? ;+360
raid_stripe_width dd ? ;+368
log_groups_per_flex db ? ;+372
ends
struct EXT4_EXTENT_HEADER ;RUS: заголовок блока экстентов/индексов
eh_magic dw ? ;RUS: в текущей реализации ext4 должно быть 0xF30A
eh_entries dw ? ;RUS: количество экстентов/индексов в блоке
eh_max dw ? ;RUS: max количество (используется при записи)
eh_depth dw ? ;RUS: глубина дерева (0, если это блок экстентов)
eh_generation dd ? ;???
ends
struct EXT4_EXTENT ;RUS: экстент ;ENG: extent
ee_block dd ? ;RUS: номер ext4 блока ;ENG: number of ext4 block
ee_len dw ? ;RUS: длина экстента ;ENG: extent length
ee_start_hi dw ? ;RUS: старшие 16 бит 48-битного адреса (пока не используются в KOS)
;ENG: upper 16 bits of the 48-bit address (not used in KolibriOS yet)
ee_start_lo dd ? ;RUS: младшие 32 бита 48-битного адреса
;ENG: lower 32 bits of the 48-bit address
ends
struct EXT4_EXTENT_IDX ;RUS: индекс - указатель на блок с экстентами/индексами
;ENG: index - pointer to block of extents/indexes
ei_block dd ? ;RUS: номер ext4 блока ;ENG: number of ext4 block
ei_leaf_lo dd ? ;RUS: младшие 32 бит 48-битного адреса
;ENG: lower 32 bits of the 48-bit address
ei_leaf_hi dw ? ;RUS: старшие 16 бит 48-битного адреса (пока не используются в KOS)
;ENG: upper 16 bits of the 48-bit address (not used in KolibriOS yet)
ei_unused dw ? ;RUS: зарезервировано ;ENG: reserved
ends
struct EXTFS PARTITION
Lock MUTEX
log_block_size dd ?
block_size dd ?
count_block_in_block dd ?
blocks_per_group dd ?
global_desc_table dd ?
root_inode dd ? ; pointer to root inode in memory
inode_size dd ?
count_pointer_in_block dd ? ; block_size / 4
count_pointer_in_block_square dd ? ; (block_size / 4)**2
ext2_save_block dd ? ;RUS: блок на глобальную 1 процедуру ;ENG: block for 1 global procedure
ext2_temp_block dd ? ;RUS: блок для мелких процедур ;ENG: block for small procedures
ext2_save_inode dd ? ;RUS: inode на глобальную процедуру ;ENG: inode for global procedure
ext2_temp_inode dd ? ;RUS: inode для мелких процедур ;ENG: inode for small procedures
groups_count dd ?
superblock rd 512/4
ends
iglobal
align 4
ext2_user_functions:
dd ext2_free
dd (ext2_user_functions_end - ext2_user_functions - 4) / 4
dd ext2_Read
dd ext2_ReadFolder
dd ext2_Rewrite
dd ext2_Write
dd ext2_SetFileEnd
dd ext2_GetFileInfo
dd ext2_SetFileInfo
dd 0
dd ext2_Delete
dd ext2_CreateFolder
ext2_user_functions_end:
endg
proc ext2_create_partition
push ebx
mov eax, 2 ;superblock start at 1024b
add ebx, 512 ; get pointer to fs-specific buffer
call fs_read32_sys
cmp [ebx + EXT2_SB_STRUC.log_block_size], 3 ;0,1,2,3
ja .no
cmp [ebx + EXT2_SB_STRUC.magic], 0xEF53
jne .no
cmp [ebx + EXT2_SB_STRUC.state], 1 ;EXT_VALID_FS=1
jne .no
cmp [ebx + EXT2_SB_STRUC.inodes_per_group], 0
je .no
mov eax, [ebx + EXT2_SB_STRUC.feature_incompat]
test eax, EXT2_FEATURE_INCOMPAT_FILETYPE
jz .no
test eax, not EXT4_FEATURE_INCOMPAT_SUPP
jz ext2_setup
.no:
; No, this superblock isn't EXT2
pop ebx
xor eax, eax
ret
; OK, this is correct EXT2 superblock
ext2_setup:
movi eax, sizeof.EXTFS
call malloc
test eax, eax
jz ext2_create_partition.no
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+EXTFS.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+EXTFS.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+EXTFS.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+EXTFS.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+EXTFS.Disk], ecx
mov [eax+EXTFS.FSUserFunctions], ext2_user_functions
push ebp esi edi
mov ebp, eax
lea ecx, [eax+EXTFS.Lock]
call mutex_init
mov esi, ebx
lea edi, [ebp+EXTFS.superblock]
mov ecx, 512/4
rep movsd ; copy sb to reserved mem
mov eax, [ebx + EXT2_SB_STRUC.blocks_count]
sub eax, [ebx + EXT2_SB_STRUC.first_data_block]
dec eax
xor edx, edx
div [ebx + EXT2_SB_STRUC.blocks_per_group]
inc eax
mov [ebp+EXTFS.groups_count], eax
mov ecx, [ebx + EXT2_SB_STRUC.log_block_size]
inc ecx
mov [ebp+EXTFS.log_block_size], ecx ; 1, 2, 3, 4 equ 1kb, 2kb, 4kb, 8kb
mov eax, 1
shl eax, cl
mov [ebp+EXTFS.count_block_in_block], eax
shl eax, 7
mov [ebp+EXTFS.count_pointer_in_block], eax
mov edx, eax ;RUS: потом еще квадрат найдем ;ENG: we'll find a square later
shl eax, 2
mov [ebp+EXTFS.block_size], eax
push eax eax ; 2 kernel_alloc
mov eax, edx
mul edx
mov [ebp+EXTFS.count_pointer_in_block_square], eax
call kernel_alloc
mov [ebp+EXTFS.ext2_save_block], eax ; and for temp block
call kernel_alloc
mov [ebp+EXTFS.ext2_temp_block], eax ; and for get_inode proc
movzx eax, word [ebx + EXT2_SB_STRUC.inode_size]
mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group]
mov [ebp+EXTFS.inode_size], eax
mov [ebp+EXTFS.blocks_per_group], ecx
push eax eax eax ;3 kernel_alloc
call kernel_alloc
mov [ebp+EXTFS.ext2_save_inode], eax
call kernel_alloc
mov [ebp+EXTFS.ext2_temp_inode], eax
call kernel_alloc
mov [ebp+EXTFS.root_inode], eax
mov ebx, eax
mov eax, EXT2_ROOT_INO
call ext2_get_inode ; read root inode
mov eax, ebp ; return pointer to EXTFS
pop edi esi ebp ebx
ret
endp
proc ext2_free
push ebp
xchg ebp, eax
stdcall kernel_free, [ebp+EXTFS.ext2_save_block]
stdcall kernel_free, [ebp+EXTFS.ext2_temp_block]
stdcall kernel_free, [ebp+EXTFS.ext2_save_inode]
stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode]
stdcall kernel_free, [ebp+EXTFS.root_inode]
xchg ebp, eax
call free
pop ebp
ret
endp
proc ext2_lock
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_lock
endp
proc ext2_unlock
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_unlock
endp
;==================================================================
;read ext2 block form FS to memory
;in: eax = i_block (address of block in ext2 terms)
; ebx = pointer to return memory
; ebp = pointer to EXTFS
;out: eax - error code (0 = no_error)
ext2_get_block:
push ebx ecx
mov ecx, [ebp+EXTFS.log_block_size]
shl eax, cl
mov ecx, eax
push [ebp+EXTFS.count_block_in_block]
@@:
mov eax, ecx
call fs_read32_sys
test eax, eax
jnz .fail
inc ecx
add ebx, 512
dec dword [esp]
jnz @B
pop ecx
xor eax, eax
@@:
pop ecx ebx
ret
.fail:
mov eax, ERROR_DEVICE
jmp @B
;===================================================================
;RUS: получает номер блока из extent inode ;ENG: receives block number from extent inode
;RUS: in: ecx = номер блока по порядку ;ENG: in: ecx = consecutive block number
;RUS: esi = адрес extent header`а ;ENG: esi = address of extent header
;RUS: ebp = указатель на структуру EXTFS ;ENG: ebp = pointer to EXTFS
;RUS: out: ecx - адрес очередного блока в случае успеха ;ENG: out: ecx - address of next block, if successful
;RUS: eax - номер ошибки (если равно 0, то ошибки нет) ;ENG: eax - error number (0 - 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_get_block
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
;===================================================================
;получает адрес ext2 блока из inode с определнным номером
;RUS: in: ecx = номер блока в inode (0..) ;ENG: in: ecx = number of block in inode (0..)
;RUS: esi = адрес inode ;ENG: esi = inode address
;RUS: ebp = указатель на структуру EXTFS;ENG: ebp = pointer to EXTFS
;RUS: out: ecx = адрес очередного блока ;ENG: out: ecx = next block address
;RUS: eax - error code ;ENG: eax - error code
ext2_get_inode_block:
test [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
jz @F
pushad
add esi, EXT2_INODE_STRUC.i_block ;esi - extent_header
call ext4_block_recursive_search
mov PUSHAD_ECX, ecx
mov PUSHAD_EAX, eax
popad
ret
@@:
cmp ecx, 12 ; 0..11 - direct block address
jb .get_direct_block
sub ecx, 12
cmp ecx, [ebp+EXTFS.count_pointer_in_block] ; 12.. - indirect blocks
jb .get_indirect_block
sub ecx, [ebp+EXTFS.count_pointer_in_block]
cmp ecx, [ebp+EXTFS.count_pointer_in_block_square]
jb .get_double_indirect_block
sub ecx, [ebp+EXTFS.count_pointer_in_block_square]
;triple indirect block
push edx ebx
mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
mov ebx, [ebp+EXTFS.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz .fail
xor edx, edx
mov eax, ecx
div [ebp+EXTFS.count_pointer_in_block_square]
;RUS: eax - номер в полученном блоке edx - номер дальше
;ENG: eax - current block number, edx - next block number
mov eax, [ebx + eax*4]
call ext2_get_block
test eax, eax
jnz .fail
mov eax, edx
jmp @F
.get_double_indirect_block:
push edx ebx
mov eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
mov ebx, [ebp+EXTFS.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz .fail
mov eax, ecx
@@:
xor edx, edx
div [ebp+EXTFS.count_pointer_in_block]
mov eax, [ebx + eax*4]
call ext2_get_block
test eax, eax
jnz .fail
mov ecx, [ebx + edx*4]
.fail:
pop ebx edx
ret
.get_indirect_block:
push ebx
mov eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
mov ebx, [ebp+EXTFS.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz @F ;RUS: если не было ошибки ;ENG: if there was no error
mov ecx, [ebx + ecx*4] ;RUS: заносим результат ;ENG: ???
@@:
pop ebx
ret
.get_direct_block:
mov ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4]
xor eax, eax
ret
;===================================================================
;get content inode by num
;in: eax = inode_num
; ebx = address of inode content
; ebp = pointer to EXTFS
;out: eax - error code
ext2_get_inode:
pushad
mov edi, ebx ;сохраним адрес inode
dec eax
xor edx, edx
div [ebp + EXT2_SB_STRUC.inodes_per_group + EXTFS.superblock]
push edx ;locale num in group
mov edx, 32
mul edx ; address block_group in global_desc_table
;RUS: в eax - смещение группы с inode-ом относительно начала глобальной дескрипторной таблицы
;RUS: найдем блок в котором он находится
;ENG: in eax - inode group offset relative to global descriptor table start
;ENG: let's find the block this inode is in
div [ebp+EXTFS.block_size]
add eax, [ebp + EXT2_SB_STRUC.first_data_block + EXTFS.superblock]
inc eax
mov ebx, [ebp+EXTFS.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz .fail
add ebx, edx ;RUS: локальный номер в блоке ;ENG: local number inside block
mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table] ;RUS: номер блока - в терминах ext2
;ENG: block number - in ext2 terms
mov ecx, [ebp+EXTFS.log_block_size]
shl eax, cl
;RUS: eax - указывает на таблицу inode-ов на hdd ;ENG: eax - points to inode table on HDD
mov esi, eax ;RUS: сохраним его пока в esi ;ENG: let's save it in esi for now
;RUS: прибавим локальный адрес inode-а ;ENG: add local address of inode
pop eax ; index
mov ecx, [ebp+EXTFS.inode_size]
mul ecx ; (index * inode_size)
;RUS: поделим на размер блока ;ENG: divide by block size
mov ecx, eax
and ecx, 512 - 1
shrd eax, edx, 9
add eax, esi ;RUS: нашли адрес блока для чтения ;ENG: found block address to read
mov ebx, [ebp+EXTFS.ext2_temp_block]
call fs_read32_sys
test eax, eax
jnz .fail
mov esi, ecx ;RUS: добавим "остаток" ;ENG: add the "remainder"
mov ecx, [ebp+EXTFS.inode_size]
add esi, ebx ;RUS: к адресу ;ENG: to the address
rep movsb ;RUS: копируем inode ;ENG: copy inode
xor eax, eax
.fail:
mov PUSHAD_EAX, eax
popad
ret
;----------------------------------------------------------------
; ext2_ReadFolder - EXT2FS implementation of reading a folder
; in: ebp = pointer to EXTFS structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
ext2_ReadFolder:
call ext2_lock
cmp byte [esi], 0
jz .root_folder
push ebx
stdcall ext2_find_lfn, [esp+4+4] ;вернет в esi адрес inode
pop ebx
test eax, eax
jnz .error_ret
test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jz .error_not_found
jmp @F
.root_folder:
mov esi, [ebp+EXTFS.root_inode]
test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jz .error_root
;придется копировать inode
mov edi, [ebp+EXTFS.ext2_save_inode]
mov ecx, [ebp+EXTFS.inode_size]
shr ecx, 2
push edi
rep movsd
pop esi
@@:
cmp [esi + EXT2_INODE_STRUC.i_size], 0 ;папка пуста
je .error_empty_dir
mov edx, [ebx + 16]
push edx ;адрес результата [edi + 28]
push 0 ;конец очередного блока папки [edi + 24]
push dword [ebx +12];сколько файлов нужно прочитать [edi + 20]
push dword [ebx + 4];первый "нужный" файл [edi + 16]
push dword [ebx + 8];флаги [edi + 12]
push 0 ;[EXT2_read_in_folder] [edi + 8]
push 0 ;[EXT2_files_in_folder] [edi + 4]
push 0 ;номер блока по порядку [edi]
mov edi, edx
mov ecx, 32/4
rep stosd ; fill header zero
mov edi, esp ; edi - указатель на локальные переменные
add edx, 32 ; edx = current mem for return
xor ecx, ecx ; получим номер первого блока
call ext2_get_inode_block
test eax, eax
jnz .error_get_block
mov eax, ecx
mov ebx, [ebp+EXTFS.ext2_save_block]
call ext2_get_block ; и считываем блок с hdd
test eax, eax
jnz .error_get_block
mov eax, ebx ; ebx = current dir record
add eax, [ebp+EXTFS.block_size]
mov [edi + 24], eax ; запомним конец очередного блока
mov ecx, [edi + 16] ; ecx = first wanted (flags ommited)
.find_wanted_start:
jecxz .find_wanted_end
.find_wanted_cycle:
cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used
jz @F
inc dword [edi + 4] ; EXT2_files_in_folder
dec ecx
@@:
movzx eax, [ebx + EXT2_DIR_STRUC.rec_len]
cmp eax, 12 ; минимальная длина записи
jb .error_bad_len
test eax, 0x3 ; длина записи должна делиться на 4
jnz .error_bad_len
sub [esi + EXT2_INODE_STRUC.i_size], eax ;вычитаем напрямую из структуры inode
add ebx, eax ; к следующей записи
cmp ebx, [edi + 24] ; сравниваем с концом блока
jb .find_wanted_start
push .find_wanted_start
.end_block: ;вылетели из цикла
cmp [esi + EXT2_INODE_STRUC.i_size], 0
jle .end_dir
inc dword [edi] ;получаем новый блок
push ecx
mov ecx, [edi]
call ext2_get_inode_block
test eax, eax
jnz .error_get_block
mov eax, ecx
mov ebx, [ebp+EXTFS.ext2_save_block]
call ext2_get_block
test eax, eax
jnz .error_get_block
pop ecx
mov eax, ebx
add eax, [ebp+EXTFS.block_size]
mov [edi + 24], eax ;запомним конец блока
ret ; опять в цикл
.wanted_end:
loop .find_wanted_cycle ; ecx 0 => -1 нужно посчитать сколько файлов
;дошли до первого "нужного" файла
.find_wanted_end:
mov ecx, [edi + 20]
.wanted_start: ; ищем first_wanted+count
jecxz .wanted_end
cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used
jz .empty_rec
inc dword [edi + 8]
inc dword [edi + 4]
push edi ecx
mov edi, edx ;обнуляем место под очереное имя файла/папки
xor eax, eax
mov ecx, 40 / 4
rep stosd
pop ecx edi
push ebx edi edx
mov eax, [ebx + EXT2_DIR_STRUC.inode] ;получим дочерний inode
mov ebx, [ebp+EXTFS.ext2_temp_inode]
call ext2_get_inode
test eax, eax
jnz .error_read_subinode
lea edi, [edx + 8]
mov eax, [ebx + EXT2_INODE_STRUC.i_ctime] ; переведем время в ntfs формат
xor edx, edx
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600
adc edx, 2
call ntfs_datetime_to_bdfe.sec
mov eax, [ebx + EXT2_INODE_STRUC.i_atime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
mov eax, [ebx + EXT2_INODE_STRUC.i_mtime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
pop edx ; пока достаем только буфер
test [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; для папки размер
jnz @F ; не возвращаем
mov eax, [ebx + EXT2_INODE_STRUC.i_size] ;low size
stosd
mov eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ;high size
stosd
xor dword [edx], FS_FT_DIR ;помечаем, что это файл(2 раза xor)
@@:
xor dword [edx], FS_FT_DIR ;помечаем, что это файл
;теперь скопируем имя, сконвертировав из UTF-8 в CP866
push ecx esi ;edi уже сохранен в стеке
mov esi, [esp+12]
movzx ecx, [esi + EXT2_DIR_STRUC.name_len]
lea edi, [edx + 40]
lea esi, [esi + EXT2_DIR_STRUC.name]
call utf8_to_cp866
and byte [edi], 0
pop esi ecx edi ebx
cmp byte [edx + 40], '.' ; в linux файл, начинающийся с точки - скрытый
jne @F
or dword [edx], FS_FT_HIDDEN
@@:
add edx, 40 + 264 ; go to next record
dec ecx ; если запись пустая ecx не надо уменьшать
.empty_rec:
movzx eax, [ebx + EXT2_DIR_STRUC.rec_len]
cmp eax, 12 ; минимальная длина записи
jb .error_bad_len
test eax, 0x3 ; длина записи должна делиться на 4
jnz .error_bad_len
sub [esi + EXT2_INODE_STRUC.i_size], eax ;вычитаем напрямую из структуры inode
add ebx, eax
cmp ebx, [edi + 24] ;дошли ли до конца блока?
jb .wanted_start
push .wanted_start ; дошли
jmp .end_block
.end_dir: ;конец папки, когда еще не дошли до нужного файла
call ext2_unlock
mov edx, [edi + 28] ;адрес структуры результата
mov ebx, [edi + 8] ;EXT2_read_in_folder
mov ecx, [edi + 4] ;EXT2_files_in_folder
mov dword [edx], 1 ;version
mov [edx + 4], ebx
mov [edx + 8], ecx
lea esp, [edi + 32]
xor eax, eax ;RUS: зарезервировано: нули в текущей реализации
;ENG: reserved: zeros in current implementation
lea edi, [edx + 12]
mov ecx, 20 / 4
rep stosd
ret
.error_bad_len:
mov eax, ERROR_FS_FAIL
.error_read_subinode:
.error_get_block:
lea esp, [edi + 32]
.error_ret:
or ebx, -1
push eax
call ext2_unlock
pop eax
ret
.error_empty_dir: ;RUS: inode папки без блоков ;ENG: inode of folder without blocks
.error_root: ;RUS: root - не папка ;ENG: root is not a folder
mov eax, ERROR_FS_FAIL
jmp .error_ret
.error_not_found: ;RUS: файл не найден ;ENG: file not found
mov eax, ERROR_FILE_NOT_FOUND
jmp .error_ret
;============================================
;convert UTF-8 string to ASCII-string (codepage 866)
;in: ecx = length source
; esi = source
; edi = buffer
; destroys: eax,esi,edi
utf8_to_cp866:
jecxz .ret
.start:
lodsw
cmp al, 0x80
jb .ascii
xchg al, ah ; big-endian
cmp ax, 0xd080
jz .yo1
cmp ax, 0xd191
jz .yo2
cmp ax, 0xd090
jb .unk
cmp ax, 0xd180
jb .rus1
cmp ax, 0xd190
jb .rus2
.unk:
mov al, '_'
jmp .doit
.yo1:
mov al, 0xf0 ; Ё capital
jmp .doit
.yo2:
mov al, 0xf1 ; ё small
jmp .doit
.rus1:
sub ax, 0xd090 - 0x80
jmp .doit
.rus2:
sub ax, 0xd18f - 0xEF
.doit:
stosb
sub ecx, 2
ja .start
ret
.ascii:
stosb
dec esi
dec ecx
jnz .start
.ret:
ret
;----------------------------------------------------------------
; ext2_Read - EXT2FS implementation of reading a file
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
ext2_Read:
call ext2_lock
cmp byte [esi], 0
jnz @F
.this_is_nofile:
call ext2_unlock
or ebx, -1
mov eax, ERROR_ACCESS_DENIED
ret
@@:
push ebx
stdcall ext2_find_lfn, [esp+4+4]
pop ebx
test eax, eax
jz @F
call ext2_unlock
or ebx, -1
mov eax, ERROR_FILE_NOT_FOUND
ret
@@:
mov ax, [esi + EXT2_INODE_STRUC.i_mode]
and ax, EXT2_S_IFMT ;оставляем только тип inode в ax
cmp ax, EXT2_S_IFREG
jne .this_is_nofile
mov edi, [ebx+16] ; edi = pointer to return mem
mov ecx, [ebx+12]
mov eax, [ebx+4]
mov edx, [ebx+8] ;RUS: edx : eax - стартовый номер байта ;ENG: edx : eax - start byte number
;RUS: ///// сравним хватит ли нам файла или нет ;ENG: ///// check if file is big enough for us
cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx
ja .size_great
jb .size_less
cmp [esi + EXT2_INODE_STRUC.i_size], eax
ja .size_great
.size_less:
call ext2_unlock
xor ebx, ebx
mov eax, ERROR_END_OF_FILE
ret
.size_great:
add eax, ecx ;RUS: add to first_wanted кол-во байт для чтения
;ENG: add to first_wanted number of bytes to read
adc edx, 0
cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx
ja .size_great_great
jb .size_great_less
cmp [esi + EXT2_INODE_STRUC.i_size], eax
jae .size_great_great ; and if it's equal, no matter where we jump
.size_great_less:
push 1 ;RUS: читаем по границе размера ;ENG: reading till the end of file
mov ecx, [esi + EXT2_INODE_STRUC.i_size]
sub ecx, [ebx+4] ;RUS: (размер - старт) = сколько читать ;ENG: to read = (size - start)
jmp @F
.size_great_great:
push 0 ;RUS: читаем столько, сколько запросили ;ENG: reading as much as requested
@@:
;здесь мы точно знаем сколько байт читать - ecx
;edi - return memory
;esi -> first wanted
push ecx ;количество считанных байт
;получим кусок из первого блока
mov edx, [ebx+8]
mov eax, [ebx+4]
div [ebp+EXTFS.block_size]
push eax ;счетчик блоков ложим в стек
push ecx
mov ecx, eax
call ext2_get_inode_block
test eax, eax
jnz .error_at_first_block
mov ebx, [ebp+EXTFS.ext2_save_block]
mov eax, ecx
call ext2_get_block
test eax, eax
jnz .error_at_first_block
pop ecx
add ebx, edx
neg edx
add edx, [ebp+EXTFS.block_size] ;RUS: block_size - стартовый байт = сколько байт 1-го блока
;ENG: block_size - start byte = number of bytes in 1st block
cmp ecx, edx
jbe .only_one_block
mov eax, ecx
sub eax, edx
mov ecx, edx
push esi
mov esi, ebx
rep movsb ;RUS: кусок 1-го блока ;ENG: part of 1st block
pop esi
;теперь в eax кол-во оставшихся байт для чтения
.calc_blocks_count:
mov ebx, edi ;чтение блока прям в ->ebx
xor edx, edx
div [ebp+EXTFS.block_size] ;кол-во байт в последнем блоке (остаток) в edx
mov edi, eax ;кол-во целых блоков в edi
@@:
test edi, edi
jz .finish_block
inc dword [esp]
mov ecx, [esp]
call ext2_get_inode_block
test eax, eax
jnz .error_at_read_cycle
mov eax, ecx ;а ebx уже забит нужным значением
call ext2_get_block
test eax, eax
jnz .error_at_read_cycle
add ebx, [ebp+EXTFS.block_size]
dec edi
jmp @B
.finish_block: ;в edx - кол-во байт в последнем блоке
test edx, edx
jz .end_read
pop ecx ;счетчик блоков -> ecx
inc ecx
call ext2_get_inode_block
test eax, eax
jnz .error_at_finish_block
mov edi, ebx
mov eax, ecx
mov ebx, [ebp+EXTFS.ext2_save_block]
call ext2_get_block
test eax, eax
jnz .error_at_finish_block
mov ecx, edx
mov esi, ebx
rep movsb ;кусок last блока
jmp @F
.end_read:
pop ecx ;счетчик блоков, который хранился в стеке
@@:
pop ebx ;количество считанных байт
call ext2_unlock
pop eax ; 1 или 0 - достигли ли конца файла
test eax, eax
jz @F
mov eax, ERROR_END_OF_FILE
ret
@@:
xor eax, eax
ret
.only_one_block:
mov esi, ebx
rep movsb ;кусок last блока
jmp .end_read
.error_at_first_block:
pop edx
.error_at_read_cycle:
pop ebx
.error_at_finish_block:
pop ecx edx
or ebx, -1
push eax
call ext2_unlock
pop eax
ret
;----------------------------------------------------------------
; in: esi = file path
; ebx = pointer to dir block
; ebp = pointer to EXTFS structure
; out: esi - name without parent or not_changed
; ebx - dir_rec of inode children
ext2_test_block_by_name:
sub esp, 256 ;EXT2_filename
mov edx, ebx
add edx, [ebp+EXTFS.block_size] ;RUS: запомним конец блока ;ENG: 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 ;RUS: кол-во байт в получившейся строке ;ENG: number of bytes in resulting string
mov esi, [esp]
@@:
jecxz .test_find
dec ecx
lodsb
call char_toupper
mov ah, [edi]
inc edi
xchg al, ah
call char_toupper
cmp al, ah
je @B
@@: ;RUS: не подошло ;ENG: didn't fit
pop esi
.next_rec:
movzx eax, [ebx + EXT2_DIR_STRUC.rec_len]
add ebx, eax ;RUS: к след. записи ;ENG: go to next record
cmp ebx, edx ;RUS: проверим конец ли ;ENG: check if this is the end
jb .start_rec
add esp, 256
ret
.test_find:
cmp byte [esi], 0
je .ret ;RUS: нашли конец ;ENG: the end reached
cmp byte [esi], '/'
jne @B
inc esi
.ret:
add esp, 256 + 4
ret
;========================
;Ищет inode по строке пути
;in: esi+[esp+4] = name
; ebp = pointer to EXTFS
;out: eax - error code
; esi = inode
; dl - первый байт из имени файла/папки
ext2_find_lfn:
mov edx, [ebp+EXTFS.root_inode]
cmp [edx + EXT2_INODE_STRUC.i_blocks], 0
je .error_empty_root
.next_path_part:
push [edx + EXT2_INODE_STRUC.i_blocks]
xor ecx, ecx
.folder_block_cycle:
push ecx
xchg esi, edx
call ext2_get_inode_block
xchg esi, edx
test eax, eax
jnz .error_get_inode_block
mov eax, ecx
mov ebx, [ebp+EXTFS.ext2_save_block] ;ebx = cur dir record
call ext2_get_block
test eax, eax
jnz .error_get_block
push esi
push edx
call ext2_test_block_by_name
pop edx
pop edi ecx
cmp edi, esi ;RUS: нашли имя? ;ENG: did we find a name?
je .next_folder_block ;RUS: не нашли -> к след. блоку ;ENG: we didn't -> moving to next block
cmp byte [esi], 0 ;RUS: дошли до "конца" пути -> возваращаемся
;ENG: reached the "end" of path -> returning
jnz @f
cmp dword [esp+8], 0
jz .get_inode_ret
mov esi, [esp+8]
mov dword [esp+8], 0
@@:
cmp [ebx + EXT2_DIR_STRUC.file_type], EXT2_FT_DIR ;RUS: нашли, но это не папка
jne .not_found ;ENG: found, but it's not a folder
mov eax, [ebx + EXT2_DIR_STRUC.inode]
mov ebx, [ebp+EXTFS.ext2_save_inode] ;RUS: все же папка. ;ENG: it's a folder afterall
call ext2_get_inode
test eax, eax
jnz .error_get_inode
pop ecx ;RUS: в стеке лежит кол-во блоков ;ENG: stack top contains number of blocks
mov edx, ebx
jmp .next_path_part
.next_folder_block:
;к следующему блоку в текущей папке
pop eax ;RUS: счетчик блоков ;ENG: 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 ;RUS: в стеке лежит кол-во блоков ;ENG: stack top contains number of blocks
mov dl, [ebx + EXT2_DIR_STRUC.name] ;RUS: в dl - первый символ () ;ENG: ???
mov eax, [ebx + EXT2_DIR_STRUC.inode]
mov ebx, [ebp+EXTFS.ext2_save_inode]
call ext2_get_inode
mov esi, ebx
xor eax, eax
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
;----------------------------------------------------------------
; ext2_GetFileInfo - EXT2 implementation of getting file info
; in: ebp = pointer to EXTFS structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
ext2_GetFileInfo:
call ext2_lock
mov edx, [ebx+16]
cmp byte [esi], 0
jz .is_root
push edx
stdcall ext2_find_lfn, [esp+4+4]
mov ebx, edx
pop edx
test eax, eax
jz @F
push eax
call ext2_unlock
pop eax
ret
.is_root:
xor ebx, ebx ;RUS: root не может быть скрытым ;ENG: root cannot be hidden
mov esi, [ebp+EXTFS.root_inode]
@@:
xor eax, eax
mov edi, edx
mov ecx, 40/4
rep stosd ; fill zero
cmp bl, '.'
jne @F
or dword [edx], FS_FT_HIDDEN
@@:
test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jnz @F
mov eax, [esi + EXT2_INODE_STRUC.i_size] ;low size
mov ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ;high size
mov dword [edx+32], eax
mov dword [edx+36], ebx
xor dword [edx], FS_FT_DIR
@@:
xor dword [edx], FS_FT_DIR
lea edi, [edx + 8]
mov eax, [esi + EXT2_INODE_STRUC.i_ctime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
mov eax, [esi + EXT2_INODE_STRUC.i_atime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
mov eax, [esi + EXT2_INODE_STRUC.i_mtime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
call ext2_unlock
xor eax, eax
ret
ext2_Rewrite:
ext2_Write:
ext2_SetFileEnd:
ext2_SetFileInfo:
ext2_Delete:
ext2_CreateFolder:
xor ebx, ebx
mov eax, ERROR_UNSUPPORTED_FS
ret