kolibrios-fun/kernel/branches/Kolibri-acpi/fs/ext2.inc

1319 lines
43 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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