kolibrios/kernel/trunk/fs/ext2.inc
turbanoff c3a49bafc1 fix ext4 dir blocks count check. fix bug in ext2_find_lfn
git-svn-id: svn://kolibrios.org@3403 a494cfbc-eb01-0410-851d-a64ba20cac60
2013-03-22 18:35:06 +00:00

1239 lines
43 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-2012. 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 ;;
;; ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$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
;флаги, указываемый в inode файла
EXT2_S_IFREG = 0x8000
EXT2_S_IFDIR = 0x4000
EXT2_S_IFMT = 0xF000 ;маска для типа файла
;флаги, указываемые в linked list родительской папки
EXT2_FT_REG_FILE = 1 ;это файл, запись в родительском каталоге
EXT2_FT_DIR = 2 ;это папка
;флаги используемые KolibriOS
FS_FT_HIDDEN = 2
FS_FT_DIR = 0x10 ;это папка
FS_FT_ASCII = 0 ;имя в ascii
FS_FT_UNICODE = 1 ;имя в unicode
EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002 ;тип файла должен указываться в директории
EXT4_FEATURE_INCOMPAT_EXTENTS = 0x0040 ;экстенты
EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x0200 ;гибкие группы блоков
;реализованные ext[234] features
EXT4_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE \
or EXT4_FEATURE_INCOMPAT_EXTENTS \
or EXT4_FEATURE_INCOMPAT_FLEX_BG
;флаги, указываемые для inode в 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 ;заголовок блока экстентов/индексов
eh_magic dw ? ;в текущей реализации ext4 должно быть 0xF30A
eh_entries dw ? ;количество экстентов/индексов в блоке
eh_max dw ? ;max количество (используется при записи)
eh_depth dw ? ;глубина дерева (0, если это блок экстентов)
eh_generation dd ? ;???
ends
struct EXT4_EXTENT ;экстент
ee_block dd ? ;номер ext4 блока
ee_len dw ? ;длина экстента
ee_start_hi dw ? ;старшие 16 бит 48-битного адреса (пока не используются в KOS)
ee_start_lo dd ? ;младшие 32 бита 48-битного адреса
ends
struct EXT4_EXTENT_IDX ;индес - указатель на блок с экстентами/индексами
ei_block dd ? ;номер ext4 блока
ei_leaf_lo dd ? ;младшие 32 бит 48-битного адреса
ei_leaf_hi dw ? ;старшие 16 бит 48-битного адреса (пока не используются в KOS)
ei_unused dw ? ;зарезервировано
ends
ext2_test_superblock:
cmp [fs_type], 0x83
jne .no
mov eax, [PARTITION_START]
add eax, 2 ;superblock start at 1024b
call hd_read
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
jnz .no
; OK, this is correct EXT2 superblock
clc
ret
.no:
; No, this superblock isn't EXT2
stc
ret
ext2_setup:
mov [fs_type], 2
push 512
call kernel_alloc ; mem for superblock
mov esi, ebx
mov edi, eax
mov ecx, 512/4
rep movsd ; copy sb to reserved mem
mov ebx, eax
mov [ext2_data.sb], eax
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 [ext2_data.groups_count], eax
mov ecx, [ebx + EXT2_SB_STRUC.log_block_size]
inc ecx
mov [ext2_data.log_block_size], ecx ; 1, 2, 3, 4 equ 1kb, 2kb, 4kb, 8kb
mov eax, 1
shl eax, cl
mov [ext2_data.count_block_in_block], eax
shl eax, 7
mov [ext2_data.count_pointer_in_block], eax
mov edx, eax ; потом еще квадрат найдем
shl eax, 2
mov [ext2_data.block_size], eax
push eax eax ; 2 kernel_alloc
mov eax, edx
mul edx
mov [ext2_data.count_pointer_in_block_square], eax
call kernel_alloc
mov [ext2_data.ext2_save_block], eax ; and for temp block
call kernel_alloc
mov [ext2_data.ext2_temp_block], eax ; and for get_inode proc
movzx ebp, word [ebx + EXT2_SB_STRUC.inode_size]
mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group]
mov [ext2_data.inode_size], ebp
mov [ext2_data.blocks_per_group], ecx
push ebp ebp ebp ;3 kernel_alloc
call kernel_alloc
mov [ext2_data.ext2_save_inode], eax
call kernel_alloc
mov [ext2_data.ext2_temp_inode], eax
call kernel_alloc
mov [ext2_data.root_inode], eax
mov ebx, eax
mov eax, EXT2_ROOT_INO
call ext2_get_inode ; read root inode
jmp return_from_part_set
;==================================================================
;read ext2 block form FS to memory
;in: eax = i_block (address of block in ext2 terms)
; ebx = pointer to return memory
;out: eax - error code (0 = no_error)
ext2_get_block:
push ebx ecx
mov ecx, [ext2_data.log_block_size]
shl eax, cl
add eax, [PARTITION_START]
mov ecx, [ext2_data.count_block_in_block]
@@:
call hd_read
cmp [hd_error], 0
jnz .fail
inc eax
add ebx, 512
loop @B
xor eax, eax
@@:
pop ecx ebx
ret
.fail:
mov eax, ERROR_DEVICE
jmp @B
;===================================================================
;получает номер блока из extent inode
;in: ecx = номер блока по порядку
; ebp = адрес extent header`а
;out: ecx - адрес очередного блока в случае успеха
; eax - номер ошибки (если равно 0, то ошибки нет)
ext4_block_recursive_search:
cmp word [ebp + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC
jne .fail
movzx ebx, [ebp + EXT4_EXTENT_HEADER.eh_entries]
add ebp, sizeof.EXT4_EXTENT_HEADER
cmp word [ebp - 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, [ebp + EXT4_EXTENT_IDX.ei_block]
jb .fail
cmp ecx, [ebp + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса
jb .end_search_index ;следующий дальше - значит текущий, то что нам нужен
add ebp, sizeof.EXT4_EXTENT_IDX
dec ebx
jmp @B
.end_search_index:
;ebp указывает на нужный extent_idx, считываем следующий блок
mov ebx, [ext2_data.ext2_temp_block]
mov eax, [ebp + EXT4_EXTENT_IDX.ei_leaf_lo]
call ext2_get_block
test eax, eax
jnz .fail
mov ebp, ebx
jmp ext4_block_recursive_search ;рекурсивно прыгаем в начало
.leaf_block: ;листовой блок ebp - ext4_extent
;цикл по экстентам
@@:
test ebx, ebx
jz .fail ;ни один узел не подошел - ошибка
mov edx, [ebp + EXT4_EXTENT.ee_block]
cmp ecx, edx
jb .fail ;если меньше, значит он был в предыдущих блоках -> ошибка
movzx edi, [ebp + EXT4_EXTENT.ee_len]
add edx, edi
cmp ecx, edx
jb .end_search_extent ;нашли нужный блок
add ebp, sizeof.EXT4_EXTENT
dec ebx
jmp @B
.end_search_extent:
mov edx, [ebp + EXT4_EXTENT.ee_start_lo]
sub ecx, [ebp + EXT4_EXTENT.ee_block] ;разница в ext4 блоках
add ecx, edx
xor eax, eax
ret
.fail:
mov eax, ERROR_FS_FAIL
ret
;===================================================================
;получает адрес ext2 блока из inode с определнным номером
;in: ecx = номер блока в inode (0..)
; ebp = адрес inode
;out: ecx = адрес очередного блока
; eax - error code
ext2_get_inode_block:
test [ebp + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
jz @F
pushad
add ebp, EXT2_INODE_STRUC.i_block ;ebp - 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, [ext2_data.count_pointer_in_block] ; 12.. - indirect blocks
jb .get_indirect_block
sub ecx, [ext2_data.count_pointer_in_block]
cmp ecx, [ext2_data.count_pointer_in_block_square]
jb .get_double_indirect_block
sub ecx, [ext2_data.count_pointer_in_block_square]
;triple indirect block
push edx ebx
mov eax, [ebx + EXT2_INODE_STRUC.i_block + 14*4]
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz .fail
xor edx, edx
mov eax, ecx
div [ext2_data.count_pointer_in_block_square]
;eax - номер в полученном блоке edx - номер дальше
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, [ebp + EXT2_INODE_STRUC.i_block + 13*4]
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz .fail
mov eax, ecx
@@:
xor edx, edx
div [ext2_data.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, [ebp + EXT2_INODE_STRUC.i_block + 12*4]
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz @F ;если не было ошибки
mov ecx, [ebx + ecx*4] ;заносим результат
@@:
pop ebx
ret
.get_direct_block:
mov ecx, [ebp + 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
;out: eax - error code
ext2_get_inode:
pushad
mov edi, ebx ;сохраним адрес inode
dec eax
xor edx, edx
mov ecx, [ext2_data.sb]
div [ecx + EXT2_SB_STRUC.inodes_per_group]
push edx ;locale num in group
mov edx, 32
mul edx ; address block_group in global_desc_table
; в eax - смещение группы с inode-ом относительно начала глобальной дескрипторной таблицы
; найдем блок в котором он находится
div [ext2_data.block_size]
add eax, [ecx + EXT2_SB_STRUC.first_data_block]
inc eax
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
test eax, eax
jnz .fail
add ebx, edx ; локальный номер в блоке
mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table]; номер блока - в терминах ext2
mov ecx, [ext2_data.log_block_size]
shl eax, cl
add eax, [PARTITION_START] ; а старт раздела - в терминах hdd (512)
;eax - указывает на таблицу inode-ов на hdd
mov esi, eax ;сохраним его пока в esi
; прибавим локальный адрес inode-а
pop eax ; index
mov ecx, [ext2_data.inode_size]
mul ecx ; (index * inode_size)
mov ebp, 512
div ebp ;поделим на размер блока
add eax, esi ;нашли адрес блока для чтения
mov ebx, [ext2_data.ext2_temp_block]
call hd_read
cmp [hd_error], 0
jnz .fail
mov esi, edx ;добавим "остаток"
add esi, ebx ;к адресу
rep movsb ;копируем inode
xor eax, eax
.fail:
mov PUSHAD_EAX, eax
popad
ret
;----------------------------------------------------------------
;
; ext2_HdReadFolder - read disk folder
;
; esi points to filename
; ebx pointer to structure 32-bit number = first wanted block, 0+
; & flags (bitfields)
; flags: bit 0: 0=ANSI names, 1=UNICODE names
; ecx number of blocks to read, 0+
; edx mem location to return data
;
; ret ebx = blocks read or 0xffffffff folder not found
; eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
ext2_HdReadFolder:
cmp byte [esi], 0
jz .root_folder
push ebx ecx edx
call ext2_find_lfn ;вернет в ebp адрес inode
pop edx ecx ebx
test eax, eax
jnz .error_ret
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jz .error_not_found
jmp @F
.root_folder:
mov ebp, [ext2_data.root_inode]
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jz .error_root
;придется копировать inode
push ecx
mov esi, ebp
mov edi, [ext2_data.ext2_save_inode]
mov ecx, [ext2_data.inode_size]
shr ecx, 2
mov ebp, edi
rep movsd
pop ecx
@@:
cmp [ebp + EXT2_INODE_STRUC.i_size], 0 ;папка пуста
je .error_empty_dir
push edx ;адрес результата [edi + 28]
push 0 ;конец очередного блока папки [edi + 24]
push ecx ;сколько файлов нужно прочитать [edi + 20]
push dword [ebx] ;первый "нужный" файл [edi + 16]
push dword [ebx + 4];флаги [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, [ext2_data.ext2_save_block]
call ext2_get_block ; и считываем блок с hdd
test eax, eax
jnz .error_get_block
mov esi, ebx ; esi = current dir record
add ebx, [ext2_data.block_size]
mov [edi + 24], ebx ; запомним конец очередного блока
mov ecx, [edi + 16] ; ecx = first wanted (flags ommited)
.find_wanted_start:
jecxz .find_wanted_end
.find_wanted_cycle:
cmp [esi + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used
jz @F
inc dword [edi + 4] ; EXT2_files_in_folder
dec ecx
@@:
movzx ebx, [esi + EXT2_DIR_STRUC.rec_len]
cmp ebx, 12 ; минимальная длина записи
jb .error_bad_len
test ebx, 0x3 ; длина записи должна делиться на 4
jnz .error_bad_len
sub [ebp + EXT2_INODE_STRUC.i_size], ebx ;вычитаем напрямую из структуры inode
add esi, ebx ; к следующей записи
cmp esi, [edi + 24] ; сравниваем с концом блока
jb .find_wanted_start
push .find_wanted_start
.end_block: ;вылетели из цикла
cmp [ebp + 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, [ext2_data.ext2_save_block]
call ext2_get_block
test eax, eax
jnz .error_get_block
pop ecx
mov esi, ebx
add ebx, [ext2_data.block_size]
mov [edi + 24], ebx ;запомним конец блока
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 [esi + 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 esi edi edx
mov eax, [esi + EXT2_DIR_STRUC.inode] ;получим дочерний inode
mov ebx, [ext2_data.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 ;edi и esi уже сохранены в стеке
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 ecx edi esi
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 ebx, [esi + EXT2_DIR_STRUC.rec_len]
cmp ebx, 12 ; минимальная длина записи
jb .error_bad_len
test ebx, 0x3 ; длина записи должна делиться на 4
jnz .error_bad_len
sub [ebp + EXT2_INODE_STRUC.i_size], ebx ;вычитаем напрямую из структуры inode
add esi, ebx
cmp esi, [edi + 24] ;дошли ли до конца блока?
jb .wanted_start
push .wanted_start ; дошли
jmp .end_block
.end_dir: ;конец папки, когда еще не дошли до нужного файла
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 ;зарезервировано: нули в текущей реализации
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
ret
.error_empty_dir: ;inode папки без блоков
.error_root: ;root - не папка
mov eax, ERROR_FS_FAIL
jmp .error_ret
.error_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_HdRead - read hard disk
;
; esi points to filename
; ebx pointer to 64-bit number = first wanted byte, 0+
; may be ebx=0 - start from first byte
; ecx number of bytes to read, 0+
; edx mem location to return data
;
; ret ebx = bytes read or 0xffffffff file not found
; eax = 0 ok read or other = errormsg
;--------------------------------------------------------------
ext2_HdRead:
cmp byte [esi], 0
jnz @F
.this_is_nofile:
or ebx, -1
mov eax, ERROR_ACCESS_DENIED
ret
@@:
push ecx ebx edx
call ext2_find_lfn
pop edx ebx ecx
test eax, eax
jz @F
or ebx, -1
mov eax, ERROR_FILE_NOT_FOUND
ret
@@:
mov ax, [ebp + EXT2_INODE_STRUC.i_mode]
and ax, EXT2_S_IFMT ;оставляем только тип inode в ax
cmp ax, EXT2_S_IFREG
jne .this_is_nofile
mov edi, edx ; edi = pointer to return mem
test ebx, ebx
jz @F
mov esi, ebx ; esi = pointer to first_wanted
mov ebx, [esi+4]
mov eax, [esi] ; ebx : eax - стартовый номер байта
;///// сравним хватит ли нам файла или нет
cmp [ebp + EXT2_INODE_STRUC.i_dir_acl], ebx
ja .size_great
jb .size_less
cmp [ebp + EXT2_INODE_STRUC.i_size], eax
ja .size_great
.size_less:
xor ebx, ebx
mov eax, ERROR_END_OF_FILE
ret
@@:
xor ebx, ebx
xor eax, eax
.size_great:
add eax, ecx ;add to first_wanted кол-во байт для чтения
adc ebx, 0
cmp [ebp + EXT2_INODE_STRUC.i_dir_acl], ebx
ja .size_great_great
jb .size_great_less
cmp [ebp + EXT2_INODE_STRUC.i_size], eax
jae .size_great_great
.size_great_less:
push 1 ;читаем по границе размера
mov ecx, [ebp + EXT2_INODE_STRUC.i_size]
sub ecx, [esi] ;(размер - старт) = сколько читать
jmp @F
.size_great_great:
push 0 ;читаем столько сколько запросили
@@:
;здесь мы точно знаем сколько байт читать - ecx
;edi - return memory
;esi -> first wanted
push ecx ;количество считанных байт
test esi, esi
jz .zero_start
;получим кусок из первого блока
mov edx, [esi+4]
mov eax, [esi]
div [ext2_data.block_size]
push eax ;счетчик блоков ложим в стек
push ecx
mov ecx, eax
call ext2_get_inode_block
test eax, eax
jnz .error_at_first_block
mov ebx, [ext2_data.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, [ext2_data.block_size] ;block_size - стартовый байт = сколько байт 1-го блока
cmp ecx, edx
jbe .only_one_block
mov eax, ecx
sub eax, edx
mov ecx, edx
mov esi, ebx
rep movsb ;кусок 1-го блока
jmp .calc_blocks_count
.zero_start:
mov eax, ecx
push 0 ;счетчик блоков ложим в стек
;теперь в eax кол-во оставшихся байт для чтения
.calc_blocks_count:
mov ebx, edi ;чтение блока прям в ->ebx
xor edx, edx
div [ext2_data.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, [ext2_data.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, [ext2_data.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 ;количество считанных байт
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
ret
;----------------------------------------------------------------
; in: esi = file path
; ebx = pointer to dir block
; 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, [ext2_data.block_size] ;запомним конец блока
.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 ;кол-во байт в получившейся строке
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
@@: ;не подошло
pop esi
.next_rec:
movzx eax, [ebx + EXT2_DIR_STRUC.rec_len]
add ebx, eax ;к след. записи
cmp ebx, edx ;проверим конец ли
jb .start_rec
add esp, 256
ret
.test_find:
cmp byte [esi], 0
je .ret ;нашли конец
cmp byte [esi], '/'
jne @B
inc esi
.ret:
add esp, 256 + 4
ret
;========================
;Ищет inode по строке пути
;in: esi = name
;out: eax - error code
; ebp = inode
; dl - первый байт из имени файла/папки
ext2_find_lfn:
mov ebp, [ext2_data.root_inode]
cmp [ebp + EXT2_INODE_STRUC.i_blocks], 0
je .error_empty_root
.next_path_part:
push [ebp + EXT2_INODE_STRUC.i_blocks]
xor ecx, ecx
.folder_block_cycle:
push ecx
call ext2_get_inode_block
test eax, eax
jnz .error_get_inode_block
mov eax, ecx
mov ebx, [ext2_data.ext2_save_block] ;ebx = cur dir record
call ext2_get_block
test eax, eax
jnz .error_get_block
push esi
call ext2_test_block_by_name
pop edi ecx
cmp edi, esi ;нашли имя?
je .next_folder_block ;не нашли -> к след. блоку
cmp byte [esi], 0 ;дошли до "конца" пути -> возваращаемся
jz .get_inode_ret
cmp [ebx + EXT2_DIR_STRUC.file_type], EXT2_FT_DIR ;нашли, но это не папка
jne .not_found
mov eax, [ebx + EXT2_DIR_STRUC.inode]
mov ebx, [ext2_data.ext2_save_inode] ;все же папка.
call ext2_get_inode
test eax, eax
jnz .error_get_inode
pop ecx ;в стеке лежит кол-во блоков
mov ebp, ebx
jmp .next_path_part
.next_folder_block:
;к следующему блоку в текущей папке
pop eax ;счетчик блоков
sub eax, [ext2_data.count_block_in_block]
jle .not_found
push eax
inc ecx
jmp .folder_block_cycle
.not_found:
mov eax, ERROR_FILE_NOT_FOUND
ret
.get_inode_ret:
pop ecx ;в стеке лежит кол-во блоков
mov dl, [ebx + EXT2_DIR_STRUC.name] ;в dl - первый символ ()
mov eax, [ebx + EXT2_DIR_STRUC.inode]
mov ebx, [ext2_data.ext2_save_inode]
call ext2_get_inode
mov ebp, ebx
xor eax, eax
ret
.error_get_inode_block:
.error_get_block:
pop ecx
.error_get_inode:
pop ebx
.error_empty_root:
mov eax, ERROR_FS_FAIL
ret
;----------------------------------------------------------------
;ext2_HdGetFileInfo - read file info from block device
;
;in: esi points to filename
; edx mem location to return data
;--------------------------------------------------------------
ext2_HdGetFileInfo:
xchg bx, bx
cmp byte [esi], 0
jz .is_root
push edx
call ext2_find_lfn
mov ebx, edx
pop edx
test eax, eax
jz @F
ret
.is_root:
xor ebx, ebx ;root не может быть скрытым
mov ebp, [ext2_data.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 [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jnz @F
mov eax, [ebp + EXT2_INODE_STRUC.i_size] ;low size
mov ebx, [ebp + 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, [ebp + EXT2_INODE_STRUC.i_ctime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
mov eax, [ebp + EXT2_INODE_STRUC.i_atime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
mov eax, [ebp + EXT2_INODE_STRUC.i_mtime]
xor edx, edx
add eax, 3054539008
adc edx, 2
call ntfs_datetime_to_bdfe.sec
xor eax, eax
ret
ext2_HdRewrite:
ext2_HdWrite:
ext2_HdSetFileEnd:
ext2_HdSetFileInfo:
ext2_HdDelete:
ext2_HdCreateFolder:
xor ebx, ebx
mov eax, ERROR_UNSUPPORTED_FS
ret