;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; 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_IROTH = 0x0002 EXT2_S_IROTH = 0x0001 EXT2_FT_REG_FILE = 1 ;это файл, запись в родительском каталоге EXT2_FT_DIR = 2 ;это папка FS_FT_DIR = 0x10 ;это папка FS_FT_ASCII = 0 ;имя в ascii FS_FT_UNICODE = 1 ;имя в unicode uglobal EXT2_files_in_folder dd ? ;всего файлов в папке EXT2_read_in_folder dd ? ;сколько файлов "считали" EXT2_end_block dd ? ;конец очередного блока папки EXT2_counter_blocks dd ? EXT2_filename db 256 dup ? 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 ext2_test_superblock: mov eax, [PARTITION_START] add eax, 2 ;superblock start at 1024b call hd_read cmp [fs_type], 0x83 jne .no 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 ; OK, this is correct EXT2 superblock clc ret .no: ; No, this superblock isn't EXT2 stc ret ext2_setup: mov [fs_type], 2 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 eax ; 3 kernel_alloc mov eax, edx mul edx mov [ext2_data.count_pointer_in_block_square], eax call kernel_alloc mov [ext2_data.global_desc_table],eax ; reserve mem for gdt 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 eax, [ebx+20] ; first_data_block mov [ext2_data.inode_size], ebp mov [ext2_data.blocks_per_group], ecx mov [ext2_data.inodes_per_group], edx mov ebx, [ext2_data.global_desc_table] inc eax ; first_data_block + 1 = gdt call ext2_get_block ; read gtd 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 popad call free_hd_channel and [hd1_status], 0 ret ;================================================================== ;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 mov edx, 32 mul edx ; address block_group in global_desc_table add eax, [ext2_data.global_desc_table] mov eax, [eax+8] ; номер блока - в терминах ext2 mov ecx, [ext2_data.log_block_size] shl eax, cl add eax, [PARTITION_START] ; а старт раздела - в терминах hdd (512) ;eax - указывает на таблицу inode-ов на hdd mov ecx, eax ;сохраним его пока в ecx ; прибавим локальный адрес inode-а pop eax ; index mul [ext2_data.inode_size] ; (index * inode_size) mov ebp, 512 div ebp ;поделим на размер блока add eax, ecx ;нашли адрес блока для чтения 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] @@: movzx ebx, [eax+EXT2_DIR_STRUC.rec_len] add eax, ebx ; к следующей записи cmp eax, [EXT2_end_block] ; проверяем "конец" jae .end_block_find_wanted loop .find_wanted_cycle .find_wanted_end: mov ecx, edi .wanted_start: ; ищем first_wanted+count jecxz .find_wanted_cycle ; ecx=0 => огромный цикл до конца папки 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 cmp [eax + EXT2_DIR_STRUC.file_type], EXT2_FT_DIR ;папка или нет jz @F push eax ;получим размер, если это файл mov eax, [eax + EXT2_DIR_STRUC.inode] mov ebx, [ext2_data.ext2_temp_inode] call ext2_get_inode mov eax, [ebx + EXT2_INODE_STRUC.i_size] ;low size mov ebx, [ebx + 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 - 2 раза pop eax @@: xor dword [edx], FS_FT_DIR 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 ;rep movsb pop esi ecx eax and byte [edi], 0 add edx, 40 + 264 ; go to next record dec ecx ; если запись пустая ecx не надо уменьшать .empty_rec: movzx ebx, [eax + EXT2_DIR_STRUC.rec_len] add eax, ebx cmp eax, [EXT2_end_block] jb .wanted_start .end_block_wanted: ;вылетели из цикла wanted mov ebx, [ext2_data.count_block_in_block] sub [EXT2_counter_blocks], ebx jz .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 dec ecx mov eax, ebx add ebx, [ext2_data.block_size] mov [EXT2_end_block], ebx jmp .wanted_start .end_block_find_wanted: ;вылетили из цикла find_wanted mov ebx, [ext2_data.count_block_in_block] sub [EXT2_counter_blocks], ebx jz .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 dec ecx mov eax, ebx add ebx, [ext2_data.block_size] mov [EXT2_end_block], ebx jmp .find_wanted_start .end_dir: 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 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 - стартовый номер байта ; mov edx, [ebp + EXT2_INODE_STRUC.i_dir_acl] ; mov ecx, [ebp + EXT2_INODE_STRUC.i_size] ;edx : ecx - размер файла 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: pop ecx xor ebx, ebx mov eax, 6 ;EOF 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, 6 ;EOF ret @@: xor eax, eax ret ;======================== ;in : esi -> name not save register ;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 eax, [ebx + EXT2_DIR_STRUC.inode] mov ebx, [ext2_data.ext2_save_inode] call ext2_get_inode mov ebp, ebx clc ret ;======================== ext2_HdRewrite: ; xchg bx, bx xor ebx, ebx mov eax, ERROR_UNSUPPORTED_FS ret ext2_HdWrite: ; xchg bx, bx xor ebx, ebx mov eax, ERROR_UNSUPPORTED_FS ret ext2_HdSetFileEnd: ; xchg bx, bx xor ebx, ebx mov eax, ERROR_UNSUPPORTED_FS 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] .doit2: xor eax, eax mov edi, edx mov ecx, 40/4 rep stosd ; fill zero test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR jz @F or dword [edx], FS_FT_DIR @@: mov byte [edx+1], FS_FT_ASCII 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 eax, eax ret ext2_HdSetFileInfo: ; xchg bx, bx xor ebx, ebx mov eax, ERROR_UNSUPPORTED_FS ret ext2_HdDelete: ; xchg bx, bx xor ebx, ebx mov eax, ERROR_UNSUPPORTED_FS ret