kolibrios-fun/kernel/trunk/fs/ext2.inc
turbanoff 5a063e44a7 Fixed bug when working with a large number of groups of blocks
git-svn-id: svn://kolibrios.org@1419 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-02-17 17:26:25 +00:00

1319 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-2010. 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
;type inode
EXT2_S_IFREG = 0x8000
EXT2_S_IFDIR = 0x4000
;user inode right's
EXT2_S_IRUSR = 0x0100
EXT2_S_IWUSR = 0x0080
EXT2_S_IXUSR = 0x0040
;group inode right's
EXT2_S_IRGRP = 0x0020
EXT2_S_IWGRP = 0x0010
EXT2_S_IXGRP = 0x0008
;other inode right's
EXT2_S_IROTH = 0x0004
EXT2_S_IWOTH = 0x0002
EXT2_S_IXOTH = 0x0001
EXT2_777_MODE = EXT2_S_IROTH or EXT2_S_IWOTH or EXT2_S_IXOTH or \
EXT2_S_IRGRP or EXT2_S_IWGRP or EXT2_S_IXGRP or \
EXT2_S_IRUSR or EXT2_S_IWUSR or EXT2_S_IXUSR
EXT2_FT_REG_FILE = 1 ;это файл, запись в родительском каталоге
EXT2_FT_DIR = 2 ;это папка
FS_FT_HIDDEN = 2
FS_FT_DIR = 0x10 ;это папка
FS_FT_ASCII = 0 ;имя в ascii
FS_FT_UNICODE = 1 ;имя в unicode
EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002
uglobal
EXT2_files_in_folder dd ? ;всего файлов в папке
EXT2_read_in_folder dd ? ;сколько файлов "считали"
EXT2_end_block dd ? ;конец очередного блока папки
EXT2_counter_blocks dd ?
EXT2_filename db 256 dup ?
EXT2_parent_name db 256 dup ?
EXT2_name_len dd ?
endg
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 dd 15 dup ?
.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 ?
.inode_bitmap dd ?
.inode_table dd ?
.free_blocks_count dw ?
.free_inodes_count dw ?
.used_dirs_count dw ?
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 db 16 dup ? ;+104
.volume_name db 16 dup ? ;+120
.last_mounted db 64 dup ? ;+136
.algo_bitmap dd ? ;+200
.prealloc_blocks db ? ;+204
.preallock_dir_blocks db ? ;+205
dw ? ;+206 alignment
.journal_uuid db 16 dup ? ;+208
.journal_inum dd ? ;+224
.journal_dev dd ? ;+228
.last_orphan dd ? ;+232
.hash_seed dd 4 dup ? ;+236
.def_hash_version db ? ;+252
db 3 dup ? ;+253 reserved
.default_mount_options dd ? ;+256
.first_meta_bg dd ? ;+260
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 dword [ebx+24], 3 ;s_block_size 0,1,2,3
ja .no
cmp word [ebx+56], 0xEF53 ;s_magic
jne .no
cmp word [ebx+58], 1 ;s_state (EXT_VALID_FS=1)
jne .no
mov eax, [ebx+96]
test eax, EXT2_FEATURE_INCOMPAT_FILETYPE
jz .no
test eax, not EXT2_FEATURE_INCOMPAT_FILETYPE
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+24]
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+88]
mov ecx, [ebx+32]
mov edx, [ebx+40]
mov [ext2_data.inode_size], ebp
mov [ext2_data.blocks_per_group], ecx
mov [ext2_data.inodes_per_group], edx
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
;==================================================================
;in: eax = i_block
; ebx = pointer to return memory
ext2_get_block:
push eax 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
inc eax
add ebx, 512
loop @B
pop ecx ebx eax
ret
;===================================================================
; in: ecx = номер блока в inode (0..)
; ebp = адрес inode
; out: ecx = адрес очередного блока
ext2_get_inode_block:
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 block
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]
;.get_triple_indirect_block:
push eax edx ebx
mov eax, [ebx + EXT2_INODE_STRUC.i_block + 14*4]
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
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
mov eax, edx
jmp @F
.get_double_indirect_block:
push eax edx ebx
mov eax, [ebp + EXT2_INODE_STRUC.i_block + 13*4]
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
mov eax, ecx
@@:
xor edx, edx
div [ext2_data.count_pointer_in_block]
mov eax, [ebx + eax*4]
call ext2_get_block
mov ecx, [ebx + edx*4]
pop ebx edx eax
ret
.get_indirect_block:
push eax ebx
mov eax, [ebp + EXT2_INODE_STRUC.i_block + 12*4]
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
mov ecx, [ebx + ecx*4]
pop ebx eax
ret
.get_direct_block:
mov ecx, dword [ebp + EXT2_INODE_STRUC.i_block + ecx*4]
ret
;===================================================================
;get content inode by num
;in: eax = inode_num
; ebx = address of inode content
ext2_get_inode:
pushad
mov edi, ebx ;сохраним адрес inode
dec eax
xor edx, edx
div [ext2_data.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]
mov ecx, [ext2_data.sb]
add eax, [ecx + EXT2_SB_STRUC.first_data_block]
inc eax
mov ebx, [ext2_data.ext2_temp_block]
call ext2_get_block
add ebx, edx ; локальный номер в блоке
mov eax, [ebx+8] ; номер блока - в терминах 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
mov esi, edx ;добавим "остаток"
add esi, ebx ;к адресу
; mov ecx, [ext2_data.inode_size]
rep movsb ;копируем inode
popad
ret
;----------------------------------------------------------------
; in: esi -> children
; ebx -> pointer to dir block
; out: esi -> name without parent or not_changed
; ebx -> dir_rec of inode children or trash
ext2_test_block_by_name:
push eax ecx edx edi
mov edx, ebx
add edx, [ext2_data.block_size] ;запомним конец блока
.start_rec:
cmp [ebx + EXT2_DIR_STRUC.inode], 0
jz .next_rec
push esi
movzx ecx, [ebx + EXT2_DIR_STRUC.name_len]
mov edi, EXT2_filename
lea esi, [ebx + EXT2_DIR_STRUC.name]
call utf8toansi_str
mov ecx, edi
sub ecx, EXT2_filename ;кол-во байт в получившейся строке
mov edi, EXT2_filename
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
jmp .ret
.test_find:
cmp byte [esi], 0
je .find ;нашли конец
cmp byte [esi], '/'
jne @B
inc esi
.find:
pop eax ;удаляем из стека сохраненое значение
.ret:
pop edi edx ecx eax
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 .doit
push ecx ebx
call ext2_find_lfn
jnc .doit2
pop ebx
.not_found:
pop ecx
or ebx, -1
mov eax, ERROR_FILE_NOT_FOUND
ret
.doit:
mov ebp, [ext2_data.root_inode]
push ecx
jmp @F
.doit2:
pop ebx
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
jz .not_found
@@:
xor eax, eax
mov edi, edx
mov ecx, 32/4
rep stosd ; fill header zero
pop edi ; edi = число блоков для чтения
push edx ebx
;--------------------------------------------- final step
and [EXT2_read_in_folder], 0
and [EXT2_files_in_folder], 0
mov eax, [ebp + EXT2_INODE_STRUC.i_blocks]
mov [EXT2_counter_blocks], eax
add edx, 32 ; (header pointer in stack) edx = current mem for return
xor esi, esi ; esi = номер блока по порядку
.new_block_folder: ;reserved label
mov ecx, esi ; получим номер блока
call ext2_get_inode_block
mov eax, ecx
mov ebx, [ext2_data.ext2_save_block]
call ext2_get_block ; и считываем блок с hdd
mov eax, ebx ; eax = current dir record
add ebx, [ext2_data.block_size]
mov [EXT2_end_block], ebx ; запомним конец очередного блока
pop ecx
mov ecx, [ecx] ; ecx = first wanted (flags ommited)
.find_wanted_start:
jecxz .find_wanted_end
.find_wanted_cycle:
cmp [eax + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used
jz @F
inc [EXT2_files_in_folder]
dec ecx
@@:
movzx ebx, [eax+EXT2_DIR_STRUC.rec_len]
cmp ebx, 12 ; минимальная длина записи
jb .end_error
test ebx, 0x3 ; длина записи должна делиться на 4
jnz .end_error
add eax, ebx ; к следующей записи
cmp eax, [EXT2_end_block] ; проверяем "конец"
jb .find_wanted_start
push .find_wanted_start
.end_block: ;вылетили из цикла
mov ebx, [ext2_data.count_block_in_block]
sub [EXT2_counter_blocks], ebx
jbe .end_dir
inc esi ;получаем новый блок
push ecx
mov ecx, esi
call ext2_get_inode_block
mov eax, ecx
mov ebx, [ext2_data.ext2_save_block]
call ext2_get_block
pop ecx
mov eax, ebx
add ebx, [ext2_data.block_size]
mov [EXT2_end_block], ebx
ret ; опять в цикл
.wanted_end:
loop .find_wanted_cycle ; ecx = -1
.find_wanted_end:
mov ecx, edi
.wanted_start: ; ищем first_wanted+count
jecxz .wanted_end
cmp [eax + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used
jz .empty_rec
inc [EXT2_files_in_folder]
inc [EXT2_read_in_folder]
mov edi, edx
push eax ecx
xor eax, eax
mov ecx, 40 / 4
rep stosd
pop ecx eax
push eax esi edx ;получим inode
mov eax, [eax + EXT2_DIR_STRUC.inode]
mov ebx, [ext2_data.ext2_temp_inode]
call ext2_get_inode
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
@@:
xor dword [edx], FS_FT_DIR
pop esi eax
or dword [edx+4], FS_FT_ASCII ; symbol type in name
;теперь скопируем имя, сконвертировав из UTF-8 в CP866
push eax ecx esi
movzx ecx, [eax + EXT2_DIR_STRUC.name_len]
lea edi, [edx + 40]
lea esi, [eax + EXT2_DIR_STRUC.name]
call utf8toansi_str
pop esi ecx eax
and byte [edi], 0
cmp byte [edx + 40], '.'
jne @F
or dword [edx], FS_FT_HIDDEN
@@:
add edx, 40 + 264 ; go to next record
dec ecx ; если запись пустая ecx не надо уменьшать
.empty_rec:
movzx ebx, [eax + EXT2_DIR_STRUC.rec_len]
cmp ebx, 12 ; минимальная длина записи
jb .end_error
test ebx, 0x3 ; длина записи должна делиться на 4
jnz .end_error
add eax, ebx
cmp eax, [EXT2_end_block]
jb .wanted_start
push .wanted_start ; дошли до конца очередного блока
jmp .end_block
.end_dir:
pop eax ; мусор (адрес возврата в цикл)
.end_error:
pop edx
mov ebx, [EXT2_read_in_folder]
mov ecx, [EXT2_files_in_folder]
mov dword [edx], 1 ;version
xor eax, eax
mov [edx+4], ebx
mov [edx+8], ecx
lea edi, [edx + 12]
mov ecx, 20 / 4
rep stosd
ret
;====================== end ext2_HdReadFolder
utf8toansi_str:
; convert UTF-8 string to ASCII-string (codepage 866)
; in: ecx=length source, esi->source, edi->buffer
; destroys: eax,esi,edi
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
call ext2_find_lfn
pop ebx ecx
jnc .doit
;.not_found:
or ebx, -1
mov eax, ERROR_FILE_NOT_FOUND
ret
.doit:
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
jz .this_is_nofile
;-----------------------------------------------------------------------------final step
mov edi, edx ; edi = pointer to return mem
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
.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:
or [EXT2_files_in_folder], 1 ;читаем по границе размера
mov ecx, [ebp + EXT2_INODE_STRUC.i_size]
sub ecx, [esi] ;(размер - старт)
jmp @F
.size_great_great:
and [EXT2_files_in_folder], 0 ;читаем столько сколько запросили
@@:
push ecx ;save for return
test esi, esi
jz .zero_start
;пока делаем п..ц криво =)
mov edx, [esi+4]
mov eax, [esi]
div [ext2_data.block_size]
mov [EXT2_counter_blocks], eax ;номер блока запоминаем
push ecx
mov ecx, eax
call ext2_get_inode_block
mov ebx, [ext2_data.ext2_save_block]
mov eax, ecx
call ext2_get_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 @F
.zero_start:
mov eax, ecx
;теперь в eax кол-во оставшихся байт для чтения
@@:
mov ebx, edi ;чтение блока прям в ->ebx
xor edx, edx
div [ext2_data.block_size] ;кол-во байт в последнем блоке (остаток) в edx
mov edi, eax ;кол-во целых блоков в edi
@@:
test edi, edi
jz .finish_block
inc [EXT2_counter_blocks]
mov ecx, [EXT2_counter_blocks]
call ext2_get_inode_block
mov eax, ecx ;а ebx уже забит нужным значением
call ext2_get_block
add ebx, [ext2_data.block_size]
dec edi
jmp @B
.finish_block: ;в edx - кол-во байт в последнем блоке
test edx, edx
jz .end_read
mov ecx, [EXT2_counter_blocks]
inc ecx
call ext2_get_inode_block
mov edi, ebx
mov eax, ecx
mov ebx, [ext2_data.ext2_save_block]
call ext2_get_block
mov ecx, edx
.only_one_block:
mov esi, ebx
rep movsb ;кусок last блока
.end_read:
pop ebx
cmp [EXT2_files_in_folder], 0
jz @F
mov eax, ERROR_END_OF_FILE
ret
@@:
xor eax, eax
ret
;========================
;in : esi -> name not save: eax ebx ecx
;out: ebp -> inode cf=0
; ebp -> trash cf=1
ext2_find_lfn:
mov ebp, [ext2_data.root_inode]
.next_folder:
or [EXT2_counter_blocks], -1 ;счетчик блоков папки cur block of inode
mov eax, [ebp + EXT2_INODE_STRUC.i_blocks] ;убывающий счетчик блоков
add eax, [ext2_data.count_block_in_block]
mov [EXT2_end_block], eax
.next_block_folder:
mov eax, [ext2_data.count_block_in_block]
sub [EXT2_end_block], eax
jz .not_found
inc [EXT2_counter_blocks]
mov ecx, [EXT2_counter_blocks]
call ext2_get_inode_block
mov eax, ecx
mov ebx, [ext2_data.ext2_save_block] ;ebx = cur dir record
call ext2_get_block
mov eax, esi
call ext2_test_block_by_name
cmp eax, esi ;нашли имя?
jz .next_block_folder
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
mov ebp, ebx
jmp .next_folder
.not_found:
stc
ret
.get_inode_ret:
mov [EXT2_end_block], ebx ; сохраняем указатеть на dir_rec
mov eax, [ebx + EXT2_DIR_STRUC.inode]
mov ebx, [ext2_data.ext2_save_inode]
call ext2_get_inode
mov ebp, ebx
clc
ret
;========================
ext2_HdGetFileInfo:
cmp byte [esi], 0
jz .doit
call ext2_find_lfn
jnc .doit2
;.not_found:
mov eax, ERROR_FILE_NOT_FOUND
ret
.doit:
mov ebp, [ext2_data.root_inode]
mov ebx, .doit ;неважно что лишь бы этому адресу не '.'
jmp @F
.doit2:
mov ebx, [EXT2_end_block]
add ebx, EXT2_DIR_STRUC.name
@@:
xor eax, eax
mov edi, edx
mov ecx, 40/4
rep stosd ; fill zero
cmp byte [ebx], '.'
jnz @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, [ebx + EXT2_INODE_STRUC.i_ctime]
xor edx, edx
add eax, 3054539008
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
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
;----------------------------------------------------------------
;
; ext2_HdCreateFolder - create new folder
;
; esi points to filename
;
; ret eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
cmp byte [esi], 0
jz .not_found
cmp byte [esi], '/'
jz .not_found
mov ebx, esi ; save source pointer
xor edi, edi ; slah pointer
@@:
lodsb
cmp al, 0
jz .zero
cmp al, '/'
jz .slash
jmp @B
.slash:
lodsb
cmp al, 0
jz .zero ; уберем слеш из имени
cmp al, '/'
jz .not_found
mov edi, esi ; edi -> next symbol after '/'
dec edi
jmp @B
.zero:
dec esi
test edi, edi
jz .doit
;слеш был
mov eax, esi
sub eax, edi
mov [EXT2_name_len], eax
mov ecx, edi
sub ecx, ebx
dec ecx ;выкинули '/' из имени ролителя
mov esi, ebx
mov edi, EXT2_parent_name
rep movsb
; esi - pointer to last slash
mov edx, esi
mov esi, EXT2_parent_name
call ext2_find_lfn
jnc .doit2
.not_found:
or ebx, -1
mov eax, ERROR_FILE_NOT_FOUND
ret
.doit:
mov ebp, [ext2_data.root_inode]
mov edx, ebx ; имя создаваемой папки
sub esi, ebx
mov [EXT2_name_len], esi
.doit2:
;ebp -> parent_inode ebx->name_new_folder [EXT2_name_len]=length of name
; стратегия выбора группы для нового inode: (так делает линукс)
; 1) Ищем группу в которой меньше всего папок и в есть свободное место
; 2) Если такая группа не нашлась, то берем группу в которой больше свободного места
call ext2_balloc
jmp ext2_HdDelete
push ebx
push ebp
mov ecx, [ext2_data.sb]
cmp [ecx + EXT2_SB_STRUC.free_inodes_count],0 ; есть ли место для inode
jz .no_space
mov eax, [ecx + EXT2_SB_STRUC.free_block_count]
sub eax, [ecx + EXT2_SB_STRUC.r_block_count]
cmp eax, 2 ; и как минимум на 2 блока
jb .no_space
mov ecx, [ext2_data.groups_count]
mov esi, [ext2_data.global_desc_table]
mov edi, -1 ;указатель на лучшую группу
mov edx, 0
.find_group_dir:
jecxz .end_find_group_dir
movzx eax, [esi + EXT2_BLOCK_GROUP_DESC.free_inodes_count]
cmp eax, edx
jbe @F
cmp [esi + EXT2_BLOCK_GROUP_DESC.free_blocks_count], 0
jz @F
mov edi, esi
movzx edx, [esi + EXT2_BLOCK_GROUP_DESC.free_inodes_count]
@@:
dec ecx
add esi, 32 ;размер структуры
jmp .find_group_dir
.end_find_group_dir:
cmp edx, 0
jz .no_space
;нашли группу, получим битовую карту inode-ов (найдем locale number)
mov eax, [edi + EXT2_BLOCK_GROUP_DESC.inode_bitmap]
mov ebx, [ext2_data.ext2_save_block]
call ext2_get_block
;теперь цикл по всем битам
mov esi, ebx
mov ecx, [ext2_data.inodes_per_group]
shr ecx, 5 ;делим на 32
mov ebp, ecx ; всего сохраним в ebp
or eax, -1 ; ищем первый свободный inode (!= -1)
repne scasd
jnz .test_last_dword ;нашли или нет
mov eax, [esi-4]
sub ebp, ecx
dec ebp
shl ebp, 5 ; глобальный номер локального номера
mov ecx, 32
@@:
test eax, 1
jz @F
shr eax, 1
loop @B
@@:
mov eax, 32
sub eax, ecx
add ebp, eax ; locale num of inode
mov eax, [esi-4]
;устанавливаем в eax крайний справа нулевой бит в 1
mov ecx, eax
inc ecx
or eax, ecx ; x | (x+1)
mov [esi-4], eax
mov ebx, [ext2_data.ext2_save_block]
mov eax, [edi + EXT2_BLOCK_GROUP_DESC.inode_bitmap]
call ext2_set_block
;считаем таблицу inode
sub edi, [ext2_data.global_desc_table]
shr edi, 5
mov eax, edi
mul [ext2_data.inodes_per_group]
add eax, ebp
inc eax ; теперь в eax (ebp) номер inode-а
mov ebp, eax
;call ext2_get_inode_address
mov ebx, [ext2_data.ext2_save_block]
call hd_read
add edx, ebx ; в edx адрес нужного inode
;забьем 0 для начала
mov edi, edx
mov ecx, [ext2_data.inode_size]
shr ecx, 2
xor eax, eax
rep stosd
mov edi, edx
mov eax, EXT2_S_IFDIR or EXT2_777_MODE
stosd ; i_mode
xor eax, eax
stosd ; i_uid
mov eax, [ext2_data.block_size]
stosd ; i_size
xor eax, eax
stosd ; i_atime
stosd ; i_ctime
stosd ; i_mtime
stosd ; i_dtime
stosd ; i_gid
inc eax
stosd ; i_links_count
mov eax, [ext2_data.count_block_in_block]
stosd ; i_blocks
.test_last_dword:
xor ebx, ebx
mov eax, ERROR_UNSUPPORTED_FS
ret
.no_space:
or ebx, -1
mov eax, ERROR_DISK_FULL
ret
;выделяет новый блок, если это можно
;иначе возвращает eax=0
ext2_balloc:
mov ecx, [ext2_data.sb]
mov eax, [ecx + EXT2_SB_STRUC.free_block_count]
sub eax, [ecx + EXT2_SB_STRUC.r_block_count]
jbe .no_space
mov ecx, [ext2_data.groups_count]
mov edi, [ext2_data.global_desc_table]
;mov esi, -1 ;указатель на лучшую группу
mov edx, 0
.find_group:
jecxz .end_find_group
movzx eax, [edi + EXT2_BLOCK_GROUP_DESC.free_blocks_count]
cmp eax, edx
jbe @F
mov esi, edi
mov edx, eax
@@:
dec ecx
add edi, 32 ;размер структуры
jmp .find_group
.end_find_group:
cmp edx, 0
jz .no_space
;нашли группу, получим битовую карту block-ов
mov eax, [esi + EXT2_BLOCK_GROUP_DESC.block_bitmap]
mov ebx, [ext2_data.ext2_save_block]
call ext2_get_block
;теперь цикл по всем битам
mov edi, ebx
mov ecx, [ext2_data.blocks_per_group]
shr ecx, 5 ;делим на 32
mov ebp, ecx ;всего сохраним в ebp
or eax, -1 ;ищем первый свободный inode (!= -1)
repe scasd
jz .test_last_dword ;нашли или нет
mov eax, [edi-4]
sub ebp, ecx
dec ebp
shl ebp, 5 ; ebp = 32*(номер div 32). Теперь найдем (номер mod 32)
mov ecx, 32
@@:
test eax, 1
jz @F
shr eax, 1
loop @B
@@:
mov eax, 32
sub eax, ecx
add ebp, eax ; ebp = номер блока в группе
mov eax, [edi-4]
mov ecx, eax
inc ecx
or eax, ecx ; x | (x+1) - устанавливает в 1 крайний справа нулевой бит (block used)
mov [edi-4], eax
mov ebx, [ext2_data.ext2_save_block]
mov eax, [esi + EXT2_BLOCK_GROUP_DESC.inode_bitmap]
; call ext2_set_block ; и пишем на hdd новую битовую маску
;============== тут получаем номер блока
mov eax, [ext2_data.blocks_per_group]
sub esi, [ext2_data.global_desc_table]
shr esi, 5 ;esi - номер группы
mul esi
add ebp, eax ;(номер_группы) * (blocks_per_group) + локальный номер в группе
mov eax, [ext2_data.sb]
add ebp, [eax + EXT2_SB_STRUC.first_data_block]
;теперь поправим глобальную дескрипторную таблицу и суперблок
mov ebx, [ext2_data.sb]
dec [ebx + EXT2_SB_STRUC.free_block_count]
mov eax, 2
add eax, [PARTITION_START]
call hd_write
mov eax, [ebx + EXT2_SB_STRUC.first_data_block]
inc eax
dec [esi + EXT2_BLOCK_GROUP_DESC.free_blocks_count];edi все еще указывает на группу в которой мы выделил блок
call ext2_set_block
mov eax, ebx
ret
.test_last_dword:
lodsd
mov ecx, [ext2_data.blocks_per_group]
and ecx, not (32-1) ;обнуляем все кроме последних 5 бит
mov edx, ecx
mov ebx, 1
@@:
jecxz .no_space
mov edx, ebx
or edx, eax ; тестируем очередной бит
shl ebx, 1
jmp @B
@@:
sub edx, ecx
dec edx ;номер в последнем блоке
.no_space:
xor eax, eax
ret
;in: eax = i_block
; ebx = pointer to memory
ext2_set_block:
push eax 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_write
inc eax
add ebx, 512
loop @B
pop ecx ebx eax
ret