Index: kernel/trunk/fs/ext2.inc =================================================================== --- kernel/trunk/fs/ext2.inc (revision 3700) +++ kernel/trunk/fs/ext2.inc (working copy) @@ -10,6 +10,11 @@ $Revision$ +; For fs_type. +FS_TYPE_UNDEFINED = 0 +FS_TYPE_EXT = 2 + +; Some set inodes. EXT2_BAD_INO = 1 EXT2_ROOT_INO = 2 EXT2_ACL_IDX_INO = 3 @@ -17,36 +22,70 @@ 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 +; EXT2_SUPER_MAGIC. +EXT2_SUPER_MAGIC = 0xEF53 +EXT2_VALID_FS = 1 -;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 +; Flags defining i_mode values. +EXT2_S_IFMT = 0xF000 ; Mask for file type. -;RUS: флаги используемые KolibriOS ;ENG: flags used by KolibriOS +EXT2_S_IFREG = 0x8000 ; Regular file. +EXT2_S_IFDIR = 0x4000 ; Directory. + +; File type defining values in directory entry. +EXT2_FT_REG_FILE = 1 ; Regular file. +EXT2_FT_DIR = 2 ; Directory. + +; 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 +FS_FT_DIR = 0x10 ; Directory. -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 +; ext2 partition flags. +EXT2_RO = 0x01 -;RUS: реализованные ext[234] features ;ENG: implemented ext[234] features +FS_FT_ASCII = 0 ; Name in ASCII. +FS_FT_UNICODE = 1 ; Name in Unicode. + +EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002 ; Have file type in directory entry. +EXT4_FEATURE_INCOMPAT_EXTENTS = 0x0040 ; Extents. +EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x0200 ; Flexible block groups. + +EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x0001 ; Sparse Superblock +EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x0002 ; Large file support (64-bit file size) + +; Implemented ext[2,3,4] features. EXT4_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE \ - or EXT4_FEATURE_INCOMPAT_EXTENTS \ - or EXT4_FEATURE_INCOMPAT_FLEX_BG + 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 +; Implemented features which otherwise require "read-only" mount. +EXT2_FEATURE_RO_COMPAT_SUPP = EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER \ + or EXT2_FEATURE_RO_COMPAT_LARGE_FILE +; ext4 features not support for write. +EXT4_FEATURE_INCOMPAT_W_NOT_SUPP = EXT4_FEATURE_INCOMPAT_EXTENTS \ + or EXT4_FEATURE_INCOMPAT_FLEX_BG + +; Flags specified in i_flags. +EXT2_EXTENTS_FL = 0x00080000 ; Extents. + +; Helper macros. +macro KERNEL_ALLOC store, label +{ + call kernel_alloc + mov store, eax + test eax, eax + jz label +} + +macro KERNEL_FREE data, label +{ + cmp data, 0 + jz label + push data + call kernel_free +} + struct EXT2_INODE_STRUC i_mode dw ? i_uid dw ? @@ -65,7 +104,7 @@ i_file_acl dd ? i_dir_acl dd ? i_faddr dd ? - i_osd2 dd ? ; 1..12 + i_osd2 dd ? ; 12 bytes. ends struct EXT2_DIR_STRUC @@ -73,153 +112,172 @@ rec_len dw ? name_len db ? file_type db ? - name db ? ; 0..255 + name db ? ; 255 (max) bytes. 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 + 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 + 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 + reserved 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 ? ;??? +; Header block extents. +struct EXT4_EXTENT_HEADER + eh_magic dw ? ; Magic value of 0xF30A, for ext4. + eh_entries dw ? ; Number of blocks covered by the extent. + eh_max dw ? ; Capacity of entries. + eh_depth dw ? ; Tree depth (if 0, extents in the array are not extent indexes) + 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 +; Extent. +struct EXT4_EXTENT + ee_block dd ? ; First logical block extent covers. + ee_len dw ? ; Number of blocks covered by extent. + ee_start_hi dw ? ; Upper 16 bits of 48-bit address (unused in KOS) + ee_start_lo dd ? ; Lower 32 bits of 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 +; Index on-disk structure; pointer to block of extents/indexes. +struct EXT4_EXTENT_IDX + ei_block dd ? ; Covers logical blocks from here. + ei_leaf_lo dd ? ; Lower 32-bits of pointer to the physical block of the next level. + ei_leaf_hi dw ? ; Higher 16-bits (unused in KOS). + ei_unused dw ? ; Reserved. ends +;--------------------------------------------------------------------- +; Check if it's a valid ext* superblock. +; Input: ebx = buffer; +; Output: carry clear if valid EXT2 superblock; set otherwise; +;--------------------------------------------------------------------- ext2_test_superblock: + ; 0x83 -> linux native filesystem (ext2fs) cmp [fs_type], 0x83 - jne .no + jne @F + ; Reading superblock starting from 1024 bytes (2nd sector). mov eax, [PARTITION_START] - add eax, 2 ;superblock start at 1024b + add eax, 2 call hd_read - cmp [ebx + EXT2_SB_STRUC.log_block_size], 3 ;0,1,2,3 - ja .no - cmp [ebx + EXT2_SB_STRUC.magic], 0xEF53 - jne .no - cmp [ebx + EXT2_SB_STRUC.state], 1 ;EXT_VALID_FS=1 - jne .no + cmp [hd_error], 0 + jne @F + + ; Allowed 1KiB, 2KiB, 4KiB, 8KiB. + cmp [ebx + EXT2_SB_STRUC.log_block_size], 3 + ja @F + + cmp [ebx + EXT2_SB_STRUC.magic], EXT2_SUPER_MAGIC + jne @F + + cmp [ebx + EXT2_SB_STRUC.state], EXT2_VALID_FS + jne @F + + ; Can't have no inodes per group. 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 + je @F + + ; If incompatible features required, unusable superblock. + mov eax, [ebx + EXT2_SB_STRUC.feature_incompat] test eax, not EXT4_FEATURE_INCOMPAT_SUPP - jnz .no + jnz @F - ; OK, this is correct EXT2 superblock + ; Clear carry to indicate EXT2 superblock. clc ret - .no: - ; No, this superblock isn't EXT2 + @@: + ; Not a (valid/usable) EXT2 superblock. stc ret +;--------------------------------------------------------------------- +; Setup ext2/3/4. +; Input: ebx = buffer; +;--------------------------------------------------------------------- ext2_setup: - mov [fs_type], 2 + mov [fs_type], FS_TYPE_EXT push 512 - call kernel_alloc ; mem for superblock + KERNEL_ALLOC [ext2_data.sb], .error + + ; Copy superblock from buffer to reserved memory. mov esi, ebx mov edi, eax mov ecx, 512/4 - rep movsd ; copy sb to reserved mem + rep movsd + mov ebx, eax - mov [ext2_data.sb], eax + ; Get total groups. mov eax, [ebx + EXT2_SB_STRUC.blocks_count] sub eax, [ebx + EXT2_SB_STRUC.first_data_block] dec eax @@ -228,85 +286,157 @@ inc eax mov [ext2_data.groups_count], eax + ; Get log(block_size), such that 1,2,3,4 equ 1KiB,2KiB,4KiB,8KiB. mov ecx, [ebx + EXT2_SB_STRUC.log_block_size] inc ecx - mov [ext2_data.log_block_size], ecx ; 1, 2, 3, 4 equ 1kb, 2kb, 4kb, 8kb + mov [ext2_data.log_block_size], ecx + ; 512-byte blocks in ext2 blocks. mov eax, 1 shl eax, cl mov [ext2_data.count_block_in_block], eax + ; Get block_size/4 (we'll find square later). shl eax, 7 mov [ext2_data.count_pointer_in_block], eax - mov edx, eax ;RUS: потом еще квадрат найдем ;ENG: we'll find a square later + mov edx, eax + ; Get block size. shl eax, 2 mov [ext2_data.block_size], eax - push eax eax ; 2 kernel_alloc + ; Save block size for 2 kernel_alloc calls. + push eax eax 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 + ; Have temporary block storage for get_inode procedure, and one for global procedure. + KERNEL_ALLOC [ext2_data.ext2_save_block], .error + KERNEL_ALLOC [ext2_data.ext2_temp_block], .error + + mov [ext2_data.partition_flags], 0x00000000 + mov eax, [ebx + EXT2_SB_STRUC.feature_ro_compat] + and eax, not EXT2_FEATURE_RO_COMPAT_SUPP + jnz .read_only + mov eax, [ebx + EXT2_SB_STRUC.feature_incompat] + and eax, EXT4_FEATURE_INCOMPAT_W_NOT_SUPP + jz @F + + .read_only: + ; Mark as read-only. + or [ext2_data.partition_flags], EXT2_RO + @@: movzx ebp, word [ebx + EXT2_SB_STRUC.inode_size] mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group] mov [ext2_data.inode_size], ebp mov [ext2_data.blocks_per_group], ecx + + ; Allocate for three inodes (loop would be overkill). + push ebp ebp ebp - 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 - + KERNEL_ALLOC [ext2_data.ext2_save_inode], .error + KERNEL_ALLOC [ext2_data.ext2_temp_inode], .error + KERNEL_ALLOC [ext2_data.root_inode], .error + + ; Read root inode. mov ebx, eax mov eax, EXT2_ROOT_INO - call ext2_get_inode ; read root inode + call ext2_get_inode + test eax, eax + jnz .error + jmp return_from_part_set -;================================================================== -;read ext2 block form FS to memory -;in: eax = i_block (address of block in ext2 terms) -; ebx = pointer to return memory -;out: eax - error code (0 = no_error) + ; Error in setting up. + .error: + mov [fs_type], FS_TYPE_UNDEFINED + + ; Free super-block memory. + KERNEL_FREE [ext2_data.sb], return_from_part_set + + ; Free save block. + KERNEL_FREE [ext2_data.ext2_save_block], return_from_part_set + + ; Temporary block. + KERNEL_FREE [ext2_data.ext2_temp_block], return_from_part_set + + ; All inodes. + KERNEL_FREE [ext2_data.ext2_save_inode], return_from_part_set + KERNEL_FREE [ext2_data.ext2_temp_inode], return_from_part_set + KERNEL_FREE [ext2_data.root_inode], return_from_part_set + + jmp return_from_part_set + +;--------------------------------------------------------------------- +; Write ext2 block from memory to disk. +; Input: eax = i_block (block number in ext2 terms); +; ebx = buffer address +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_write_block: + push edx ebx ecx + + mov edx, hd_write + jmp ext2_modify_block + +;--------------------------------------------------------------------- +; Read ext2 block from disk to memory. +; Input: eax = i_block (block number in ext2 terms); +; ebx = address of where to read block +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- ext2_get_block: - push ebx ecx + push edx ebx ecx + + mov edx, hd_read + jmp ext2_modify_block + +;--------------------------------------------------------------------- +; Modify ext2 block. +; Input: eax = i_block (block number in ext2 terms); +; ebx = I/O buffer address; +; edx = hd_write/hd_write +; edx, ebx, ecx on stack. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- +ext2_modify_block: + ; Get block number in hard-disk terms in eax. 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 + call edx cmp [hd_error], 0 jnz .fail + inc eax add ebx, 512 loop @B + xor eax, eax @@: - pop ecx ebx + pop ecx ebx edx ret + .fail: mov eax, ERROR_DEVICE jmp @B - -;=================================================================== -;RUS: получает номер блока из extent inode ;ENG: receives block number from extent inode -;RUS: in: ecx = номер блока по порядку ;ENG: in: ecx = consecutive block number -;RUS: ebp = адрес extent header`а ;ENG: ebp = address of extent header -;RUS: out: ecx - адрес очередного блока в случае успеха ;ENG: out: ecx - address of next block, if successful -;RUS: eax - номер ошибки (если равно 0, то ошибки нет) ;ENG: eax - error number (0 - no error) +; KSOC_EXT2_WRITE_END_TODO: clean this up. +;--------------------------------------------------------------------- +; Receives block number from extent-based inode. +; Input: ecx = number of block in inode +; ebp = address of extent header +; Output: ecx = address of next block, if successful +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- ext4_block_recursive_search: cmp word [ebp + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC jne .fail @@ -375,52 +505,61 @@ mov eax, ERROR_FS_FAIL ret -;=================================================================== -;получает адрес ext2 блока из inode с определнным номером -;RUS: in: ecx = номер блока в inode (0..) ;ENG: in: ecx = number of block in inode (0..) -;RUS: ebp = адрес inode ;ENG: ebp = inode address -;RUS: out: ecx = адрес очередного блока ;ENG: out: ecx = next block address -;RUS: eax - error code ;ENG: eax - error code +;--------------------------------------------------------------------- +; Receives block number from indirect-addressing inode. +; Input: ecx = number of block in inode +; ebp = address of inode +; Output: ecx = address of next block, if successful +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- ext2_get_inode_block: + ; If inode is extent-based, use ext4_block_recursive_search. test [ebp + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL jz @F pushad - add ebp, EXT2_INODE_STRUC.i_block ;ebp - extent_header + + ; Get extent header in EBP. + add ebp, EXT2_INODE_STRUC.i_block call ext4_block_recursive_search mov PUSHAD_ECX, ecx mov PUSHAD_EAX, eax + popad ret @@: - cmp ecx, 12 ; 0..11 - direct block address + ; 0 to 11: direct blocks. + cmp ecx, 12 jb .get_direct_block + ; Indirect blocks sub ecx, 12 - cmp ecx, [ext2_data.count_pointer_in_block] ; 12.. - indirect blocks + cmp ecx, [ext2_data.count_pointer_in_block] jb .get_indirect_block + ; Double indirect blocks. sub ecx, [ext2_data.count_pointer_in_block] cmp ecx, [ext2_data.count_pointer_in_block_square] jb .get_double_indirect_block - sub ecx, [ext2_data.count_pointer_in_block_square] - ;triple indirect block + ; Triple indirect blocks. + sub ecx, [ext2_data.count_pointer_in_block_square] push edx ebx + ; Get triply-indirect block in temp_block. mov eax, [ebx + EXT2_INODE_STRUC.i_block + 14*4] mov ebx, [ext2_data.ext2_temp_block] call ext2_get_block test eax, eax jnz .fail + ; Get index in triply-indirect block. xor edx, edx mov eax, ecx div [ext2_data.count_pointer_in_block_square] - ;RUS: eax - номер в полученном блоке edx - номер дальше - ;ENG: eax - current block number, edx - next block number + ; eax: index in triply-indirect block, edx: index in doubly-indirect block. mov eax, [ebx + eax*4] call ext2_get_block test eax, eax @@ -432,6 +571,7 @@ .get_double_indirect_block: push edx ebx + ; Get doubly-indirect block. mov eax, [ebp + EXT2_INODE_STRUC.i_block + 13*4] mov ebx, [ext2_data.ext2_temp_block] call ext2_get_block @@ -443,6 +583,7 @@ xor edx, edx div [ext2_data.count_pointer_in_block] + ; eax: index in doubly-indirect block, edx: index in indirect block. mov eax, [ebx + eax*4] call ext2_get_block test eax, eax @@ -455,13 +596,16 @@ .get_indirect_block: push ebx + + ; Get index of indirect block. mov eax, [ebp + EXT2_INODE_STRUC.i_block + 12*4] mov ebx, [ext2_data.ext2_temp_block] call ext2_get_block test eax, eax - jnz @F ;RUS: если не было ошибки ;ENG: if there was no error - - mov ecx, [ebx + ecx*4] ;RUS: заносим результат ;ENG: ??? + jnz @F + + ; Get the block ID. + mov ecx, [ebx + ecx*4] @@: pop ebx ret @@ -471,93 +615,98 @@ xor eax, eax ret -;=================================================================== -;get content inode by num -;in: eax = inode_num -; ebx = address of inode content -;out: eax - error code +;--------------------------------------------------------------------- +; Get content of inode by number. +; Input: eax = inode number. +; ebx = address where to store inode content. +; Output: eax = error code (0 implies no error) +;--------------------------------------------------------------------- ext2_get_inode: pushad - mov edi, ebx ;сохраним адрес inode + + mov edi, ebx ; Save the address where to store the inode. dec eax xor edx, edx mov ecx, [ext2_data.sb] + ; EAX = block group. div [ecx + EXT2_SB_STRUC.inodes_per_group] - push edx ;locale num in group + push edx ; Index in group. mov edx, 32 - mul edx ; address block_group in global_desc_table + mul edx ; Get index of descriptor 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 + ; eax: inode group offset relative to global descriptor table start + ; Find the block this inode is in. div [ext2_data.block_size] add eax, [ecx + EXT2_SB_STRUC.first_data_block] inc eax mov ebx, [ext2_data.ext2_temp_block] call ext2_get_block test eax, eax - jnz .fail + jnz .return - 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 + add ebx, edx ; edx: local number of descriptor inside block + mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table] ; Block number of inode table - in ext2 terms. mov ecx, [ext2_data.log_block_size] shl eax, cl - add eax, [PARTITION_START] ;RUS: а старт раздела - в терминах hdd (512) - ;ENG: partition start - in HDD terms (512) - ;RUS: eax - указывает на таблицу inode-ов на hdd ;ENG: eax - points to inode table on HDD - mov esi, eax ;RUS: сохраним его пока в esi ;ENG: let's save it in esi for now + add eax, [PARTITION_START] - ;RUS: прибавим локальный адрес inode-а ;ENG: add local address of inode - pop eax ; index + ; eax: points to inode table on HDD. + mov esi, eax + + ; Add local address of inode. + pop eax mov ecx, [ext2_data.inode_size] mul ecx ; (index * inode_size) + mov ebp, 512 - div ebp ;RUS: поделим на размер блока ;ENG: divide by block size + div ebp ; Divide by block size. - add eax, esi ;RUS: нашли адрес блока для чтения ;ENG: found block address to read + add eax, esi ; Found block to read. mov ebx, [ext2_data.ext2_temp_block] call hd_read cmp [hd_error], 0 - jnz .fail + jz @F - mov esi, edx ;RUS: добавим "остаток" ;ENG: add the "remainder" - add esi, ebx ;RUS: к адресу ;ENG: to the address - rep movsb ;RUS: копируем inode ;ENG: copy inode + mov eax, ERROR_DEVICE + jmp .return + + @@: + mov esi, edx ; The "remainder" is the inode address in the sector. + add esi, ebx + rep movsb + xor eax, eax - .fail: + .return: mov PUSHAD_EAX, eax popad ret -;---------------------------------------------------------------- -; -; ext2_HdReadFolder - read disk folder -; -; esi points to filename -; ebx pointer to structure 32-bit number = first wanted block, 0+ -; & flags (bitfields) -; flags: bit 0: 0=ANSI names, 1=UNICODE names -; ecx number of blocks to read, 0+ -; edx mem location to return data -; -; ret ebx = blocks read or 0xffffffff folder not found -; eax = 0 ok read or other = errormsg -; -;-------------------------------------------------------------- +;--------------------------------------------------------------------- +; Read disk folder. +; Input: esi = file name. +; ebx = pointer to structure. +; +0: first wanted block. +; +4: flags, bit 0: 0=ANSI, 1=UNICODE names. +; ecx = number of blocks to read (0+). +; edx = mem location to return data. +; Output: ebx = blocks read (or 0xFFFFFFFF, folder not found) +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- ext2_HdReadFolder: cmp byte [esi], 0 jz .root_folder push ebx ecx edx - call ext2_find_lfn ;вернет в ebp адрес inode + call ext2_find_lfn ; Get inode. pop edx ecx ebx + test eax, eax jnz .error_ret + + ; If not a directory, then return with error. test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR jz .error_not_found jmp @F @@ -566,78 +715,85 @@ mov ebp, [ext2_data.root_inode] test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR jz .error_root - ;придется копировать inode + + ; Copy the inode. push ecx mov esi, ebp + mov edi, [ext2_data.ext2_save_inode] mov ecx, [ext2_data.inode_size] shr ecx, 2 mov ebp, edi rep movsd + pop ecx @@: - cmp [ebp + EXT2_INODE_STRUC.i_size], 0 ;папка пуста + cmp [ebp + EXT2_INODE_STRUC.i_size], 0 ; Folder is empty. je .error_empty_dir - push edx ;адрес результата [edi + 28] - push 0 ;конец очередного блока папки [edi + 24] - push ecx ;сколько файлов нужно прочитать [edi + 20] - push dword [ebx] ;первый "нужный" файл [edi + 16] - push dword [ebx + 4];флаги [edi + 12] - push 0 ;[EXT2_read_in_folder] [edi + 8] - push 0 ;[EXT2_files_in_folder] [edi + 4] - push 0 ;номер блока по порядку [edi] + push edx ; Result address [edi + 28]. + push 0 ; End of the current block in folder [edi + 24] + push ecx ; Blocks to read [edi + 20] + push dword [ebx] ; The first wanted file [edi + 16] + push dword [ebx + 4] ; Flags [edi + 12] + push 0 ; Read files [edi + 8] + push 0 ; Files in folder [edi + 4] + push 0 ; Number of blocks read in dir (and current block index) [edi] + ; Fill header with zeroes. mov edi, edx mov ecx, 32/4 - rep stosd ; fill header zero + rep stosd - mov edi, esp ; edi - указатель на локальные переменные - add edx, 32 ; edx = current mem for return + mov edi, esp ; edi = pointer to local variables. + add edx, 32 ; edx = mem to return. - xor ecx, ecx ; получим номер первого блока + xor ecx, ecx ; Get number of first block. call ext2_get_inode_block test eax, eax jnz .error_get_block mov eax, ecx mov ebx, [ext2_data.ext2_save_block] - call ext2_get_block ; и считываем блок с hdd + call ext2_get_block ; Read the block. test eax, eax jnz .error_get_block - mov esi, ebx ; esi = current dir record + mov esi, ebx ; esi: current directory record add ebx, [ext2_data.block_size] - mov [edi + 24], ebx ; запомним конец очередного блока + mov [edi + 24], ebx - mov ecx, [edi + 16] ; ecx = first wanted (flags ommited) + mov ecx, [edi + 16] ; ecx = first wanted (flags ommited) .find_wanted_start: jecxz .find_wanted_end .find_wanted_cycle: - cmp [esi + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used + cmp [esi + EXT2_DIR_STRUC.inode], 0 ; Don't count unused inode in total files. jz @F - inc dword [edi + 4] ; EXT2_files_in_folder + + inc dword [edi + 4] ; EXT2 files in folder. dec ecx @@: movzx ebx, [esi + EXT2_DIR_STRUC.rec_len] - - cmp ebx, 12 ; минимальная длина записи + + cmp ebx, 12 ; Minimum record length. jb .error_bad_len - test ebx, 0x3 ; длина записи должна делиться на 4 + test ebx, 0x3 ; Record length must be divisible by four. jnz .error_bad_len - sub [ebp + EXT2_INODE_STRUC.i_size], ebx ;вычитаем напрямую из структуры inode - add esi, ebx ; к следующей записи - cmp esi, [edi + 24] ; сравниваем с концом блока + sub [ebp + EXT2_INODE_STRUC.i_size], ebx ; Subtract "processed record" length directly from inode. + add esi, ebx ; Go to next record. + cmp esi, [edi + 24] ; If not reached the next block, continue. jb .find_wanted_start push .find_wanted_start - .end_block: ;вылетели из цикла + .end_block: ; Get the next block. cmp [ebp + EXT2_INODE_STRUC.i_size], 0 jle .end_dir - inc dword [edi] ;получаем новый блок + inc dword [edi] ; Number of blocks read. + + ; Read the next block. push ecx mov ecx, [edi] call ext2_get_inode_block @@ -649,35 +805,38 @@ call ext2_get_block test eax, eax jnz .error_get_block + pop ecx - pop ecx mov esi, ebx - add ebx, [ext2_data.block_size] - mov [edi + 24], ebx ;запомним конец блока - ret ; опять в цикл + add ebx, [ext2_data.block_size] + mov [edi + 24], ebx ; Update the end of the current block variable. + ret .wanted_end: - loop .find_wanted_cycle ; ecx 0 => -1 нужно посчитать сколько файлов + loop .find_wanted_cycle ; Skip files till we reach wanted one. - ;дошли до первого "нужного" файла + ; First requisite file. .find_wanted_end: mov ecx, [edi + 20] - .wanted_start: ; ищем first_wanted+count + .wanted_start: ; Look for first_wanted + count. jecxz .wanted_end - cmp [esi + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used + + cmp [esi + EXT2_DIR_STRUC.inode], 0 ; if (inode == 0): not used; jz .empty_rec + + ; Increment "files in dir" and "read files" count. inc dword [edi + 8] inc dword [edi + 4] push edi ecx - mov edi, edx ;обнуляем место под очереное имя файла/папки + mov edi, edx ; Zero out till the name field. xor eax, eax mov ecx, 40 / 4 rep stosd pop ecx edi push esi edi edx - mov eax, [esi + EXT2_DIR_STRUC.inode] ;получим дочерний inode + mov eax, [esi + EXT2_DIR_STRUC.inode] ; Get the child inode. mov ebx, [ext2_data.ext2_temp_inode] call ext2_get_inode test eax, eax @@ -685,9 +844,9 @@ lea edi, [edx + 8] - mov eax, [ebx + EXT2_INODE_STRUC.i_ctime] ; переведем время в ntfs формат + mov eax, [ebx + EXT2_INODE_STRUC.i_ctime] ; Convert time in NTFS format. xor edx, edx - add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 + add eax, 3054539008 ; (369 * 365 + 89) * 24 * 3600 adc edx, 2 call ntfs_datetime_to_bdfe.sec @@ -703,20 +862,21 @@ adc edx, 2 call ntfs_datetime_to_bdfe.sec - pop edx ; пока достаем только буфер - test [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; для папки размер - jnz @F ; не возвращаем + pop edx + test [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; If folder, don't report size. + jnz @F - mov eax, [ebx + EXT2_INODE_STRUC.i_size] ;low size + mov eax, [ebx + EXT2_INODE_STRUC.i_size] ; Low size stosd - mov eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ;high size + 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 ; Mark as file. @@: - xor dword [edx], FS_FT_DIR ;помечаем, что это файл + xor dword [edx], FS_FT_DIR ; Mark as directory. - ;теперь скопируем имя, сконвертировав из UTF-8 в CP866 - push ecx ;edi и esi уже сохранены в стеке + ; Copy name after converting from UTF-8 to CP866. + push ecx movzx ecx, [esi + EXT2_DIR_STRUC.name_len] lea edi, [edx + 40] lea esi, [esi + EXT2_DIR_STRUC.name] @@ -724,40 +884,39 @@ and byte [edi], 0 pop ecx edi esi - cmp byte [edx + 40], '.' ; в linux файл, начинающийся с точки - скрытый + cmp byte [edx + 40], '.' ; If it begins with ".", mark it as hidden. jne @F or dword [edx], FS_FT_HIDDEN + @@: - - add edx, 40 + 264 ; go to next record - dec ecx ; если запись пустая ecx не надо уменьшать + add edx, 40 + 264 ; Go to next record. + dec ecx .empty_rec: movzx ebx, [esi + EXT2_DIR_STRUC.rec_len] - cmp ebx, 12 ; минимальная длина записи + cmp ebx, 12 ; Illegal length. jb .error_bad_len - test ebx, 0x3 ; длина записи должна делиться на 4 + test ebx, 0x3 ; Not a multiple of four. jnz .error_bad_len - sub [ebp + EXT2_INODE_STRUC.i_size], ebx ;вычитаем напрямую из структуры inode - add esi, ebx - cmp esi, [edi + 24] ;дошли ли до конца блока? + sub [ebp + EXT2_INODE_STRUC.i_size], ebx ; Subtract directly from the inode. + add esi, ebx + cmp esi, [edi + 24] ; Are we at the end of the block? jb .wanted_start push .wanted_start ; дошли jmp .end_block - .end_dir: ;конец папки, когда еще не дошли до нужного файла - mov edx, [edi + 28] ;адрес структуры результата - mov ebx, [edi + 8] ;EXT2_read_in_folder - mov ecx, [edi + 4] ;EXT2_files_in_folder - mov dword [edx], 1 ;version + .end_dir: ; End of the directory. + mov edx, [edi + 28] ; Address of where to return data. + 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 + xor eax, eax ; Reserved in current implementation. lea edi, [edx + 12] mov ecx, 20 / 4 rep stosd @@ -765,60 +924,75 @@ .error_bad_len: mov eax, ERROR_FS_FAIL + .error_read_subinode: .error_get_block: + ; Fix the stack. lea esp, [edi + 32] .error_ret: or ebx, -1 ret - .error_empty_dir: ;RUS: inode папки без блоков ;ENG: inode of folder without blocks - .error_root: ;RUS: root - не папка ;ENG: root is not a folder + .error_empty_dir: ; inode of folder without blocks. + .error_root: ; Root has to be a folder. mov eax, ERROR_FS_FAIL jmp .error_ret - .error_not_found: ;RUS: файл не найден ;ENG: file not found + .error_not_found: ; Directory 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 + +;--------------------------------------------------------------------- +; Convert UTF-8 string to ASCII-string (codepage 866) +; Input: esi = source. +; edi = buffer. +; ecx = length of source. +; Output: destroys eax, esi, edi +;--------------------------------------------------------------------- utf8_to_cp866: - jecxz .ret + ; Check for zero-length string. + jecxz .return + .start: lodsw cmp al, 0x80 jb .ascii - xchg al, ah ; big-endian + 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 + mov al, 0xf0 ; Ё capital. jmp .doit + .yo2: - mov al, 0xf1 ; ё small + mov al, 0xf1 ; ё small. jmp .doit + .rus1: sub ax, 0xd090 - 0x80 jmp .doit + .rus2: sub ax, 0xd18f - 0xEF + .doit: stosb sub ecx, 2 @@ -830,23 +1004,19 @@ dec esi dec ecx jnz .start - .ret: + + .return: 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 - -;-------------------------------------------------------------- +;--------------------------------------------------------------------- +; Read file from the hard disk. +; Input: esi = points to file name. +; ebx = pointer to 64-bit no: first byte wanted. +; ecx = number of bytes to read. +; edx = memory location to return data to. +; Output: ebx = bytes read (0xFFFFFFFF -> file not found) +; eax = error code (0 implies no error) +;--------------------------------------------------------------------- ext2_HdRead: cmp byte [esi], 0 jnz @F @@ -869,25 +1039,28 @@ @@: mov ax, [ebp + EXT2_INODE_STRUC.i_mode] - and ax, EXT2_S_IFMT ;оставляем только тип inode в ax + and ax, EXT2_S_IFMT ; Leave the file format in AX. + + ; Check if file. cmp ax, EXT2_S_IFREG jne .this_is_nofile - mov edi, edx ; edi = pointer to return mem + mov edi, edx test ebx, ebx jz @F - mov esi, ebx ; esi = pointer to first_wanted + + mov esi, ebx mov ebx, [esi+4] - mov eax, [esi] ;RUS: ebx : eax - стартовый номер байта ;ENG: ebx : eax - start byte number + mov eax, [esi] ; ebx:eax = start byte number. - ;RUS: ///// сравним хватит ли нам файла или нет ;ENG: ///// check if file is big enough for us + ; Check if file is big enough for us. cmp [ebp + EXT2_INODE_STRUC.i_dir_acl], ebx - ja .size_great + ja .size_greater jb .size_less cmp [ebp + EXT2_INODE_STRUC.i_size], eax - ja .size_great + ja .size_greater .size_less: xor ebx, ebx @@ -897,58 +1070,66 @@ @@: xor ebx, ebx xor eax, eax - .size_great: - add eax, ecx ;RUS: add to first_wanted кол-во байт для чтения - ;ENG: add to first_wanted number of bytes to read + + .size_greater: + add eax, ecx ; Get last byte. adc ebx, 0 + ; Check if we've to read whole file, or till requested. cmp [ebp + EXT2_INODE_STRUC.i_dir_acl], ebx - ja .size_great_great - jb .size_great_less + ja .read_till_requested + jb .read_whole_file cmp [ebp + EXT2_INODE_STRUC.i_size], eax - jae .size_great_great ; and if it's equal, no matter where we jump + jae .read_till_requested - .size_great_less: - push 1 ;RUS: читаем по границе размера ;ENG: reading till the end of file + .read_whole_file: + push 1 ; Read till the end of file. mov ecx, [ebp + EXT2_INODE_STRUC.i_size] - sub ecx, [esi] ;RUS: (размер - старт) = сколько читать ;ENG: to read = (size - start) + test esi, esi + jz @F + + sub ecx, [esi] ; To read = (size - starting byte) jmp @F - .size_great_great: - push 0 ;RUS: читаем столько, сколько запросили ;ENG: reading as much as requested + .read_till_requested: + push 0 ; Read as much as requested. @@: - ;здесь мы точно знаем сколько байт читать - ecx - ;edi - return memory - ;esi -> first wanted + ; ecx = bytes to read. + ; edi = return memory + ; [esi] = starting byte. - push ecx ;количество считанных байт + push ecx ; Number of bytes to read. test esi, esi jz .zero_start - ;получим кусок из первого блока - mov edx, [esi+4] + ; Get part of the first block. + mov edx, [esi + 4] mov eax, [esi] div [ext2_data.block_size] - push eax ;счетчик блоков ложим в стек + push eax ; Save block counter to stack. push ecx mov ecx, eax call ext2_get_inode_block test eax, eax jnz .error_at_first_block + mov ebx, [ext2_data.ext2_save_block] mov eax, ecx call ext2_get_block test eax, eax jnz .error_at_first_block + pop ecx + ; Get index inside block. add ebx, edx neg edx - add edx, [ext2_data.block_size] ;RUS: block_size - стартовый байт = сколько байт 1-го блока - ;ENG: block_size - start byte = number of bytes in 1st block + add edx, [ext2_data.block_size] ; Get number of bytes in this block. + + ; If it's smaller than total bytes to read, then only one block. cmp ecx, edx jbe .only_one_block @@ -957,43 +1138,52 @@ mov ecx, edx mov esi, ebx - rep movsb ;RUS: кусок 1-го блока ;ENG: part of 1st block + rep movsb ; Copy part of 1st block. jmp .calc_blocks_count .zero_start: mov eax, ecx - push 0 ;счетчик блоков ложим в стек - ;теперь в eax кол-во оставшихся байт для чтения + push 0xFFFFFFFF ; Save block counter to stack (we inc this soon, so it'll roll-over to 0). + + ; eax -> bytes to read. .calc_blocks_count: - mov ebx, edi ;чтение блока прям в ->ebx + mov ebx, edi ; Read the block in ebx. xor edx, edx - div [ext2_data.block_size] ;кол-во байт в последнем блоке (остаток) в edx - mov edi, eax ;кол-во целых блоков в edi + div [ext2_data.block_size] ; Get number of bytes in last block in edx. + mov edi, eax ; Get number of blocks in edi. + @@: + ; Test if all blocks are done. 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 уже забит нужным значением + mov eax, ecx ; ebx already contains desired values. call ext2_get_block + test eax, eax jnz .error_at_read_cycle + add ebx, [ext2_data.block_size] dec edi jmp @B - .finish_block: ;в edx - кол-во байт в последнем блоке + ; In edx -- number of bytes in the last block. + .finish_block: test edx, edx jz .end_read - pop ecx ;счетчик блоков -> ecx + pop ecx ; Pop block counter in ECX. inc ecx call ext2_get_inode_block + test eax, eax jnz .error_at_finish_block @@ -1001,19 +1191,20 @@ mov eax, ecx mov ebx, [ext2_data.ext2_save_block] call ext2_get_block + test eax, eax jnz .error_at_finish_block mov ecx, edx mov esi, ebx - rep movsb ;кусок last блока + rep movsb ; Copy last piece of block. jmp @F .end_read: - pop ecx ;счетчик блоков, который хранился в стеке + pop ecx ; Pop block counter in ECX. @@: - pop ebx ;количество считанных байт - pop eax ; 1 или 0 - достигли ли конца файла + pop ebx ; Number of bytes read. + pop eax ; If we were asked to read more, say EOF. test eax, eax jz @F @@ -1025,27 +1216,29 @@ .only_one_block: mov esi, ebx - rep movsb ;кусок last блока + rep movsb ; Copy last piece of block. jmp .end_read - .error_at_first_block: + .error_at_first_block: pop edx - .error_at_read_cycle: + .error_at_read_cycle: pop ebx - .error_at_finish_block: + .error_at_finish_block: pop ecx edx or ebx, -1 ret -;---------------------------------------------------------------- -; in: esi = file path -; ebx = pointer to dir block -; out: esi - name without parent or not_changed -; ebx - dir_rec of inode children +;--------------------------------------------------------------------- +; Find parent from file path in block. +; Input: esi = file path. +; ebx = pointer to directory block. +; Output: esi = name without parent, or not changed. +; ebx = directory record matched. +;--------------------------------------------------------------------- ext2_test_block_by_name: - sub esp, 256 ;EXT2_filename + sub esp, 256 ; Space for EXT2 filename. mov edx, ebx - add edx, [ext2_data.block_size] ;RUS: запомним конец блока ;ENG: save block end + add edx, [ext2_data.block_size] ; Save block end. .start_rec: cmp [ebx + EXT2_DIR_STRUC.inode], 0 @@ -1059,10 +1252,15 @@ mov ecx, edi lea edi, [esp + 4] - sub ecx, edi ;RUS: кол-во байт в получившейся строке ;ENG: number of bytes in resulting string + sub ecx, edi ; Number of bytes in resulting string. mov esi, [esp] + + ; esi: original file path. + ; edi: converted string stored on stack. + ; ecx: size of converted string. @@: + ; If no bytes left in resulting string, test it. jecxz .test_find dec ecx @@ -1073,42 +1271,52 @@ inc edi xchg al, ah call char_toupper + + ; If both are same, check next byte. cmp al, ah je @B - @@: ;RUS: не подошло ;ENG: didn't fit + @@: ; Doesn't match. 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 + add ebx, eax ; Go to next record. + cmp ebx, edx ; 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], '/' + je .ret ; The end reached. + cmp byte [esi], '/' ; If not end of directory name, not matched. jne @B inc esi + .ret: add esp, 256 + 4 ret -;======================== -;Ищет inode по строке пути -;in: esi = name -;out: eax - error code -; ebp = inode -; dl - первый байт из имени файла/папки +;--------------------------------------------------------------------- +; Seek inode from the path. +; Input: esi = name. +; Output: eax = error code (0 implies no error) +; ebp = inode +; dl = first byte of file/folder name. +; [ext2_data.ext2_save_inode] stores the inode. +;--------------------------------------------------------------------- ext2_find_lfn: mov ebp, [ext2_data.root_inode] + + ; Check for empty root. cmp [ebp + EXT2_INODE_STRUC.i_blocks], 0 je .error_empty_root .next_path_part: push [ebp + EXT2_INODE_STRUC.i_blocks] xor ecx, ecx + .folder_block_cycle: push ecx call ext2_get_inode_block @@ -1116,7 +1324,7 @@ jnz .error_get_inode_block mov eax, ecx - mov ebx, [ext2_data.ext2_save_block] ;ebx = cur dir record + mov ebx, [ext2_data.ext2_save_block] ; Get directory records from directory. call ext2_get_block test eax, eax jnz .error_get_block @@ -1125,28 +1333,30 @@ call ext2_test_block_by_name pop edi ecx - cmp edi, esi ;RUS: нашли имя? ;ENG: did we find a name? - je .next_folder_block ;RUS: не нашли -> к след. блоку ;ENG: we didn't -> moving to next block + cmp edi, esi ; Did something match? + je .next_folder_block ; No, move to next block. - cmp byte [esi], 0 ;RUS: дошли до "конца" пути -> возваращаемся - ;ENG: reached the "end" of path -> returning - jz .get_inode_ret + cmp byte [esi], 0 ; Reached the "end" of path successfully. + je .get_inode_ret - cmp [ebx + EXT2_DIR_STRUC.file_type], EXT2_FT_DIR ;RUS: нашли, но это не папка - jne .not_found ;ENG: found, but it's not a folder - mov eax, [ebx + EXT2_DIR_STRUC.inode] - mov ebx, [ext2_data.ext2_save_inode] ;RUS: все же папка. ;ENG: it's a folder afterall + mov ebx, [ext2_data.ext2_save_inode] call ext2_get_inode test eax, eax jnz .error_get_inode - pop ecx ;RUS: в стеке лежит кол-во блоков ;ENG: stack top contains number of blocks + + movzx eax, [ebx + EXT2_INODE_STRUC.i_mode] + and eax, EXT2_S_IFMT ; Get the mask. + cmp eax, EXT2_S_IFDIR + jne .not_found ; Matched till part, but directory entry we got doesn't point to folder. + + pop ecx ; Stack top contains number of blocks. mov ebp, ebx jmp .next_path_part .next_folder_block: - ;к следующему блоку в текущей папке - pop eax ;RUS: счетчик блоков ;ENG: blocks counter + ; Next block in current folder. + pop eax ; Get blocks counter. sub eax, [ext2_data.count_block_in_block] jle .not_found @@ -1159,13 +1369,16 @@ ret .get_inode_ret: - pop ecx ;RUS: в стеке лежит кол-во блоков ;ENG: stack top contains number of blocks - mov dl, [ebx + EXT2_DIR_STRUC.name] ;RUS: в dl - первый символ () ;ENG: ??? + pop ecx ; Stack top contains number of blocks. + + mov dl, [ebx + EXT2_DIR_STRUC.name] ; First character of file-name. mov eax, [ebx + EXT2_DIR_STRUC.inode] mov ebx, [ext2_data.ext2_save_inode] + + ; If we can't get the inode, eax contains the error. call ext2_get_inode + mov ebp, ebx - xor eax, eax ret .error_get_inode_block: @@ -1177,14 +1390,13 @@ mov eax, ERROR_FS_FAIL ret -;---------------------------------------------------------------- -;ext2_HdGetFileInfo - read file info from block device -; -;in: esi points to filename -; edx mem location to return data -;-------------------------------------------------------------- +;--------------------------------------------------------------------- +; Read file information from block device. +; Input: esi = file name. +; edx = memory location to return data. +; Output: eax = error code. +;--------------------------------------------------------------------- ext2_HdGetFileInfo: - xchg bx, bx cmp byte [esi], 0 jz .is_root @@ -1197,30 +1409,35 @@ ret .is_root: - xor ebx, ebx ;RUS: root не может быть скрытым ;ENG: root cannot be hidden + xor ebx, ebx ; Clear out first char, since we don't want to set hidden flag on root. mov ebp, [ext2_data.root_inode] + @@: xor eax, eax mov edi, edx mov ecx, 40/4 - rep stosd ; fill zero + rep stosd ; Zero fill buffer. cmp bl, '.' jne @F or dword [edx], FS_FT_HIDDEN + @@: + test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR + jnz @F ; If a directory, don't put in file size. - 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 eax, [ebp + EXT2_INODE_STRUC.i_size] ; Low file size. + mov ebx, [ebp + EXT2_INODE_STRUC.i_dir_acl] ; High file size. mov dword [edx+32], eax mov dword [edx+36], ebx - xor dword [edx], FS_FT_DIR + + xor dword [edx], FS_FT_DIR ; Next XOR will clean this, to mark it as a file. @@: - xor dword [edx], FS_FT_DIR + xor dword [edx], FS_FT_DIR ; Mark as directory. lea edi, [edx + 8] + + ; Store all time. mov eax, [ebp + EXT2_INODE_STRUC.i_ctime] xor edx, edx add eax, 3054539008 Index: kernel/trunk/fs/part_set.inc =================================================================== --- kernel/trunk/fs/part_set.inc (revision 3700) +++ kernel/trunk/fs/part_set.inc (working copy) @@ -27,7 +27,7 @@ ;****************************************************** PARTITION_START dd 0x3f PARTITION_END dd 0 -fs_type db 0 ; 1=NTFS, 2=EXT2/3, 16=FAT16, 32=FAT32 +fs_type db 0 ; 1=NTFS, 2=EXT2/3/4, 16=FAT16, 32=FAT32 align 4 fs_dependent_data_start: @@ -83,6 +83,7 @@ .ext2_temp_inode dd ? ;RUS: inode для мелких процедур ;ENG: inode for small procedures .sb dd ? ; superblock .groups_count dd ? + .partition_flags dd ? if $ > fs_dependent_data_end ERROR: increase sizeof(fs_dependent_data)!