;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2013. 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 struct EXTFS PARTITION Lock MUTEX log_block_size dd ? block_size dd ? count_block_in_block dd ? blocks_per_group dd ? global_desc_table dd ? root_inode dd ? ; pointer to root inode in memory inode_size dd ? count_pointer_in_block dd ? ; block_size / 4 count_pointer_in_block_square dd ? ; (block_size / 4)**2 ext2_save_block dd ? ;RUS: блок на глобальную 1 процедуру ;ENG: block for 1 global procedure ext2_temp_block dd ? ;RUS: блок для мелких процедур ;ENG: block for small procedures ext2_save_inode dd ? ;RUS: inode на глобальную процедуру ;ENG: inode for global procedure ext2_temp_inode dd ? ;RUS: inode для мелких процедур ;ENG: inode for small procedures groups_count dd ? superblock rd 512/4 ends iglobal align 4 ext2_user_functions: dd ext2_free dd (ext2_user_functions_end - ext2_user_functions - 4) / 4 dd ext2_Read dd ext2_ReadFolder dd ext2_Rewrite dd ext2_Write dd ext2_SetFileEnd dd ext2_GetFileInfo dd ext2_SetFileInfo dd 0 dd ext2_Delete dd ext2_CreateFolder ext2_user_functions_end: endg proc ext2_create_partition push ebx mov eax, 2 ;superblock start at 1024b add ebx, 512 ; get pointer to fs-specific buffer call fs_read32_sys 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 jz ext2_setup .no: ; No, this superblock isn't EXT2 pop ebx xor eax, eax ret ; OK, this is correct EXT2 superblock ext2_setup: movi eax, sizeof.EXTFS call malloc test eax, eax jz ext2_create_partition.no mov ecx, dword [ebp+PARTITION.FirstSector] mov dword [eax+EXTFS.FirstSector], ecx mov ecx, dword [ebp+PARTITION.FirstSector+4] mov dword [eax+EXTFS.FirstSector+4], ecx mov ecx, dword [ebp+PARTITION.Length] mov dword [eax+EXTFS.Length], ecx mov ecx, dword [ebp+PARTITION.Length+4] mov dword [eax+EXTFS.Length+4], ecx mov ecx, [ebp+PARTITION.Disk] mov [eax+EXTFS.Disk], ecx mov [eax+EXTFS.FSUserFunctions], ext2_user_functions push ebp esi edi mov ebp, eax lea ecx, [eax+EXTFS.Lock] call mutex_init mov esi, ebx lea edi, [ebp+EXTFS.superblock] mov ecx, 512/4 rep movsd ; copy sb to reserved mem 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 [ebp+EXTFS.groups_count], eax mov ecx, [ebx + EXT2_SB_STRUC.log_block_size] inc ecx mov [ebp+EXTFS.log_block_size], ecx ; 1, 2, 3, 4 equ 1kb, 2kb, 4kb, 8kb mov eax, 1 shl eax, cl mov [ebp+EXTFS.count_block_in_block], eax shl eax, 7 mov [ebp+EXTFS.count_pointer_in_block], eax mov edx, eax ;RUS: потом еще квадрат найдем ;ENG: we'll find a square later shl eax, 2 mov [ebp+EXTFS.block_size], eax push eax eax ; 2 kernel_alloc mov eax, edx mul edx mov [ebp+EXTFS.count_pointer_in_block_square], eax call kernel_alloc mov [ebp+EXTFS.ext2_save_block], eax ; and for temp block call kernel_alloc mov [ebp+EXTFS.ext2_temp_block], eax ; and for get_inode proc movzx eax, word [ebx + EXT2_SB_STRUC.inode_size] mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group] mov [ebp+EXTFS.inode_size], eax mov [ebp+EXTFS.blocks_per_group], ecx push eax eax eax ;3 kernel_alloc call kernel_alloc mov [ebp+EXTFS.ext2_save_inode], eax call kernel_alloc mov [ebp+EXTFS.ext2_temp_inode], eax call kernel_alloc mov [ebp+EXTFS.root_inode], eax mov ebx, eax mov eax, EXT2_ROOT_INO call ext2_get_inode ; read root inode mov eax, ebp ; return pointer to EXTFS pop edi esi ebp ebx ret endp proc ext2_free push ebp xchg ebp, eax stdcall kernel_free, [ebp+EXTFS.ext2_save_block] stdcall kernel_free, [ebp+EXTFS.ext2_temp_block] stdcall kernel_free, [ebp+EXTFS.ext2_save_inode] stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode] stdcall kernel_free, [ebp+EXTFS.root_inode] xchg ebp, eax call free pop ebp ret endp proc ext2_lock lea ecx, [ebp+EXTFS.Lock] jmp mutex_lock endp proc ext2_unlock lea ecx, [ebp+EXTFS.Lock] jmp mutex_unlock endp ;================================================================== ;read ext2 block form FS to memory ;in: eax = i_block (address of block in ext2 terms) ; ebx = pointer to return memory ; ebp = pointer to EXTFS ;out: eax - error code (0 = no_error) ext2_get_block: push ebx ecx mov ecx, [ebp+EXTFS.log_block_size] shl eax, cl mov ecx, eax push [ebp+EXTFS.count_block_in_block] @@: mov eax, ecx call fs_read32_sys test eax, eax jnz .fail inc ecx add ebx, 512 dec dword [esp] jnz @B pop ecx 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: esi = адрес extent header`а ;ENG: esi = address of extent header ;RUS: ebp = указатель на структуру EXTFS ;ENG: ebp = pointer to EXTFS ;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 [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC jne .fail movzx ebx, [esi + EXT4_EXTENT_HEADER.eh_entries] add esi, sizeof.EXT4_EXTENT_HEADER cmp word [esi - 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, [esi + EXT4_EXTENT_IDX.ei_block] jb .fail cmp ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса jb .end_search_index ;следующий дальше - значит текущий, то что нам нужен add esi, sizeof.EXT4_EXTENT_IDX dec ebx jmp @B .end_search_index: ;ebp указывает на нужный extent_idx, считываем следующий блок mov ebx, [ebp+EXTFS.ext2_temp_block] mov eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo] call ext2_get_block test eax, eax jnz .fail mov esi, ebx jmp ext4_block_recursive_search ;рекурсивно прыгаем в начало .leaf_block: ;листовой блок esi - ext4_extent ;цикл по экстентам @@: test ebx, ebx jz .fail ;ни один узел не подошел - ошибка mov edx, [esi + EXT4_EXTENT.ee_block] cmp ecx, edx jb .fail ;если меньше, значит он был в предыдущих блоках -> ошибка movzx edi, [esi + EXT4_EXTENT.ee_len] add edx, edi cmp ecx, edx jb .end_search_extent ;нашли нужный блок add esi, sizeof.EXT4_EXTENT dec ebx jmp @B .end_search_extent: mov edx, [esi + EXT4_EXTENT.ee_start_lo] sub ecx, [esi + 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: esi = адрес inode ;ENG: esi = inode address ;RUS: ebp = указатель на структуру EXTFS;ENG: ebp = pointer to EXTFS ;RUS: out: ecx = адрес очередного блока ;ENG: out: ecx = next block address ;RUS: eax - error code ;ENG: eax - error code ext2_get_inode_block: test [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL jz @F pushad add esi, EXT2_INODE_STRUC.i_block ;esi - 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, [ebp+EXTFS.count_pointer_in_block] ; 12.. - indirect blocks jb .get_indirect_block sub ecx, [ebp+EXTFS.count_pointer_in_block] cmp ecx, [ebp+EXTFS.count_pointer_in_block_square] jb .get_double_indirect_block sub ecx, [ebp+EXTFS.count_pointer_in_block_square] ;triple indirect block push edx ebx mov eax, [esi + EXT2_INODE_STRUC.i_block + 14*4] mov ebx, [ebp+EXTFS.ext2_temp_block] call ext2_get_block test eax, eax jnz .fail xor edx, edx mov eax, ecx div [ebp+EXTFS.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, [esi + EXT2_INODE_STRUC.i_block + 13*4] mov ebx, [ebp+EXTFS.ext2_temp_block] call ext2_get_block test eax, eax jnz .fail mov eax, ecx @@: xor edx, edx div [ebp+EXTFS.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, [esi + EXT2_INODE_STRUC.i_block + 12*4] mov ebx, [ebp+EXTFS.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, [esi + 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 ; ebp = pointer to EXTFS ;out: eax - error code ext2_get_inode: pushad mov edi, ebx ;сохраним адрес inode dec eax xor edx, edx div [ebp + EXT2_SB_STRUC.inodes_per_group + EXTFS.superblock] 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 [ebp+EXTFS.block_size] add eax, [ebp + EXT2_SB_STRUC.first_data_block + EXTFS.superblock] inc eax mov ebx, [ebp+EXTFS.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, [ebp+EXTFS.log_block_size] shl eax, cl ;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, [ebp+EXTFS.inode_size] mul ecx ; (index * inode_size) ;RUS: поделим на размер блока ;ENG: divide by block size mov ecx, eax and ecx, 512 - 1 shrd eax, edx, 9 add eax, esi ;RUS: нашли адрес блока для чтения ;ENG: found block address to read mov ebx, [ebp+EXTFS.ext2_temp_block] call fs_read32_sys test eax, eax jnz .fail mov esi, ecx ;RUS: добавим "остаток" ;ENG: add the "remainder" mov ecx, [ebp+EXTFS.inode_size] 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_ReadFolder - EXT2FS implementation of reading a folder ; in: ebp = pointer to EXTFS structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 ; out: eax, ebx = return values for sysfunc 70 ;---------------------------------------------------------------- ext2_ReadFolder: call ext2_lock cmp byte [esi], 0 jz .root_folder push ebx stdcall ext2_find_lfn, [esp+4+4] ;вернет в esi адрес inode pop ebx test eax, eax jnz .error_ret test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR jz .error_not_found jmp @F .root_folder: mov esi, [ebp+EXTFS.root_inode] test [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR jz .error_root ;придется копировать inode mov edi, [ebp+EXTFS.ext2_save_inode] mov ecx, [ebp+EXTFS.inode_size] shr ecx, 2 push edi rep movsd pop esi @@: cmp [esi + EXT2_INODE_STRUC.i_size], 0 ;папка пуста je .error_empty_dir mov edx, [ebx + 16] push edx ;адрес результата [edi + 28] push 0 ;конец очередного блока папки [edi + 24] push dword [ebx +12];сколько файлов нужно прочитать [edi + 20] push dword [ebx + 4];первый "нужный" файл [edi + 16] push dword [ebx + 8];флаги [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, [ebp+EXTFS.ext2_save_block] call ext2_get_block ; и считываем блок с hdd test eax, eax jnz .error_get_block mov eax, ebx ; ebx = current dir record add eax, [ebp+EXTFS.block_size] mov [edi + 24], eax ; запомним конец очередного блока mov ecx, [edi + 16] ; ecx = first wanted (flags ommited) .find_wanted_start: jecxz .find_wanted_end .find_wanted_cycle: cmp [ebx + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used jz @F inc dword [edi + 4] ; EXT2_files_in_folder dec ecx @@: movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] cmp eax, 12 ; минимальная длина записи jb .error_bad_len test eax, 0x3 ; длина записи должна делиться на 4 jnz .error_bad_len sub [esi + EXT2_INODE_STRUC.i_size], eax ;вычитаем напрямую из структуры inode add ebx, eax ; к следующей записи cmp ebx, [edi + 24] ; сравниваем с концом блока jb .find_wanted_start push .find_wanted_start .end_block: ;вылетели из цикла cmp [esi + 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, [ebp+EXTFS.ext2_save_block] call ext2_get_block test eax, eax jnz .error_get_block pop ecx mov eax, ebx add eax, [ebp+EXTFS.block_size] mov [edi + 24], eax ;запомним конец блока 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 [ebx + 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 ebx edi edx mov eax, [ebx + EXT2_DIR_STRUC.inode] ;получим дочерний inode mov ebx, [ebp+EXTFS.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 esi ;edi уже сохранен в стеке mov esi, [esp+12] 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 esi ecx edi ebx 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 eax, [ebx + EXT2_DIR_STRUC.rec_len] cmp eax, 12 ; минимальная длина записи jb .error_bad_len test eax, 0x3 ; длина записи должна делиться на 4 jnz .error_bad_len sub [esi + EXT2_INODE_STRUC.i_size], eax ;вычитаем напрямую из структуры inode add ebx, eax cmp ebx, [edi + 24] ;дошли ли до конца блока? jb .wanted_start push .wanted_start ; дошли jmp .end_block .end_dir: ;конец папки, когда еще не дошли до нужного файла call ext2_unlock 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 push eax call ext2_unlock pop eax 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_Read - EXT2FS implementation of reading a file ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 ; out: eax, ebx = return values for sysfunc 70 ;---------------------------------------------------------------- ext2_Read: call ext2_lock cmp byte [esi], 0 jnz @F .this_is_nofile: call ext2_unlock or ebx, -1 mov eax, ERROR_ACCESS_DENIED ret @@: push ebx stdcall ext2_find_lfn, [esp+4+4] pop ebx test eax, eax jz @F call ext2_unlock or ebx, -1 mov eax, ERROR_FILE_NOT_FOUND ret @@: mov ax, [esi + EXT2_INODE_STRUC.i_mode] and ax, EXT2_S_IFMT ;оставляем только тип inode в ax cmp ax, EXT2_S_IFREG jne .this_is_nofile mov edi, [ebx+16] ; edi = pointer to return mem mov ecx, [ebx+12] mov eax, [ebx+4] mov edx, [ebx+8] ;RUS: edx : eax - стартовый номер байта ;ENG: edx : eax - start byte number ;RUS: ///// сравним хватит ли нам файла или нет ;ENG: ///// check if file is big enough for us cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx ja .size_great jb .size_less cmp [esi + EXT2_INODE_STRUC.i_size], eax ja .size_great .size_less: call ext2_unlock xor ebx, ebx mov eax, ERROR_END_OF_FILE ret .size_great: add eax, ecx ;RUS: add to first_wanted кол-во байт для чтения ;ENG: add to first_wanted number of bytes to read adc edx, 0 cmp [esi + EXT2_INODE_STRUC.i_dir_acl], edx ja .size_great_great jb .size_great_less cmp [esi + 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, [esi + EXT2_INODE_STRUC.i_size] sub ecx, [ebx+4] ;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 ;количество считанных байт ;получим кусок из первого блока mov edx, [ebx+8] mov eax, [ebx+4] div [ebp+EXTFS.block_size] push eax ;счетчик блоков ложим в стек push ecx mov ecx, eax call ext2_get_inode_block test eax, eax jnz .error_at_first_block mov ebx, [ebp+EXTFS.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, [ebp+EXTFS.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 push esi mov esi, ebx rep movsb ;RUS: кусок 1-го блока ;ENG: part of 1st block pop esi ;теперь в eax кол-во оставшихся байт для чтения .calc_blocks_count: mov ebx, edi ;чтение блока прям в ->ebx xor edx, edx div [ebp+EXTFS.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, [ebp+EXTFS.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, [ebp+EXTFS.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 ;количество считанных байт call ext2_unlock 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 push eax call ext2_unlock pop eax ret ;---------------------------------------------------------------- ; in: esi = file path ; ebx = pointer to dir block ; ebp = pointer to EXTFS structure ; 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, [ebp+EXTFS.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+[esp+4] = name ; ebp = pointer to EXTFS ;out: eax - error code ; esi = inode ; dl - первый байт из имени файла/папки ext2_find_lfn: mov edx, [ebp+EXTFS.root_inode] cmp [edx + EXT2_INODE_STRUC.i_blocks], 0 je .error_empty_root .next_path_part: push [edx + EXT2_INODE_STRUC.i_blocks] xor ecx, ecx .folder_block_cycle: push ecx xchg esi, edx call ext2_get_inode_block xchg esi, edx test eax, eax jnz .error_get_inode_block mov eax, ecx mov ebx, [ebp+EXTFS.ext2_save_block] ;ebx = cur dir record call ext2_get_block test eax, eax jnz .error_get_block push esi push edx call ext2_test_block_by_name pop edx 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 jnz @f cmp dword [esp+8], 0 jz .get_inode_ret mov esi, [esp+8] mov dword [esp+8], 0 @@: 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, [ebp+EXTFS.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 edx, ebx jmp .next_path_part .next_folder_block: ;к следующему блоку в текущей папке pop eax ;RUS: счетчик блоков ;ENG: blocks counter sub eax, [ebp+EXTFS.count_block_in_block] jle .not_found push eax inc ecx jmp .folder_block_cycle .not_found: mov eax, ERROR_FILE_NOT_FOUND ret 4 .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, [ebp+EXTFS.ext2_save_inode] call ext2_get_inode mov esi, ebx xor eax, eax ret 4 .error_get_inode_block: .error_get_block: pop ecx .error_get_inode: pop ebx .error_empty_root: mov eax, ERROR_FS_FAIL ret 4 ;---------------------------------------------------------------- ; ext2_GetFileInfo - EXT2 implementation of getting file info ; in: ebp = pointer to EXTFS structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 ; out: eax, ebx = return values for sysfunc 70 ;---------------------------------------------------------------- ext2_GetFileInfo: call ext2_lock mov edx, [ebx+16] cmp byte [esi], 0 jz .is_root push edx stdcall ext2_find_lfn, [esp+4+4] mov ebx, edx pop edx test eax, eax jz @F push eax call ext2_unlock pop eax ret .is_root: xor ebx, ebx ;RUS: root не может быть скрытым ;ENG: root cannot be hidden mov esi, [ebp+EXTFS.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 [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR jnz @F mov eax, [esi + EXT2_INODE_STRUC.i_size] ;low size mov ebx, [esi + 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, [esi + EXT2_INODE_STRUC.i_ctime] xor edx, edx add eax, 3054539008 adc edx, 2 call ntfs_datetime_to_bdfe.sec mov eax, [esi + EXT2_INODE_STRUC.i_atime] xor edx, edx add eax, 3054539008 adc edx, 2 call ntfs_datetime_to_bdfe.sec mov eax, [esi + EXT2_INODE_STRUC.i_mtime] xor edx, edx add eax, 3054539008 adc edx, 2 call ntfs_datetime_to_bdfe.sec call ext2_unlock xor eax, eax ret ext2_Rewrite: ext2_Write: ext2_SetFileEnd: ext2_SetFileInfo: ext2_Delete: ext2_CreateFolder: xor ebx, ebx mov eax, ERROR_UNSUPPORTED_FS ret