kolibrios-fun/kernel/trunk/fs/ext2.inc

1254 lines
46 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ;;
;; 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
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 ;RUS: потом еще квадрат найдем ;ENG: we'll find a square later
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
;===================================================================
;RUS: получает номер блока из extent inode ;ENG: receives block number from extent inode
;RUS: in: ecx = номер блока по порядку ;ENG: in: ecx = consecutive block number
;RUS: ebp = адрес extent header`а ;ENG: ebp = address of extent header
;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 [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 с определнным номером
;RUS: in: ecx = номер блока в inode (0..) ;ENG: in: ecx = number of block in inode (0..)
;RUS: ebp = адрес inode ;ENG: ebp = inode address
;RUS: out: ecx = адрес очередного блока ;ENG: out: ecx = next block address
;RUS: eax - error code ;ENG: 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]
;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, [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 ;RUS: если не было ошибки ;ENG: if there was no error
mov ecx, [ebx + ecx*4] ;RUS: заносим результат ;ENG: ???
@@:
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
;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 [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 ;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, [ext2_data.log_block_size]
shl eax, cl
add eax, [PARTITION_START] ;RUS: а старт раздела - в терминах hdd (512)
;ENG: partition start - in HDD terms (512)
;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, [ext2_data.inode_size]
mul ecx ; (index * inode_size)
mov ebp, 512
div ebp ;RUS: поделим на размер блока ;ENG: divide by block size
add eax, esi ;RUS: нашли адрес блока для чтения ;ENG: found block address to read
mov ebx, [ext2_data.ext2_temp_block]
call hd_read
cmp [hd_error], 0
jnz .fail
mov esi, edx ;RUS: добавим "остаток" ;ENG: add the "remainder"
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_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 ;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
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_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] ;RUS: ebx : eax - стартовый номер байта ;ENG: ebx : eax - start byte number
;RUS: ///// сравним хватит ли нам файла или нет ;ENG: ///// check if file is big enough for us
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 ;RUS: add to first_wanted кол-во байт для чтения
;ENG: add to first_wanted number of bytes to read
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 ; 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, [ebp + EXT2_INODE_STRUC.i_size]
sub ecx, [esi] ;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 ;количество считанных байт
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] ;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
mov esi, ebx
rep movsb ;RUS: кусок 1-го блока ;ENG: part of 1st block
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] ;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 = 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 ;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
jz .get_inode_ret
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, [ext2_data.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 ebp, ebx
jmp .next_path_part
.next_folder_block:
;к следующему блоку в текущей папке
pop eax ;RUS: счетчик блоков ;ENG: blocks counter
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 ;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, [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 ;RUS: root не может быть скрытым ;ENG: root cannot be hidden
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