Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 3912 → Rev 3913

/kernel/trunk/blkdev/disk.inc
1006,6 → 1006,9
call ext2_create_partition
test eax, eax
jnz .success
call xfs_create_partition
test eax, eax
jnz .success
; 3. No file system has recognized the volume, so just allocate the PARTITION
; structure without extra fields.
movi eax, sizeof.PARTITION
/kernel/trunk/fs/xfs.asm
0,0 → 1,2769
include 'xfs.inc'
 
;
; This file contains XFS related code.
; For more information on XFS check sources below.
;
; 1. XFS Filesystem Structure, 2nd Edition, Revision 1. Silicon Graphics Inc. 2006
; 2. Linux source http://kernel.org
;
 
 
; test partition type (valid XFS one?)
; alloc and fill XFS (see xfs.inc) structure
; this function is called for each partition
; returns 0 (not XFS or invalid) / pointer to partition structure
xfs_create_partition:
push ebx ecx edx esi edi
cmp dword[ebx + xfs_sb.sb_magicnum], XFS_SB_MAGIC ; signature
jne .error
 
; TODO: check XFS.versionnum and XFS.features2
; print superblock params for debugging (waiting for bug reports)
 
movi eax, sizeof.XFS
call malloc
test eax, eax
jz .error
 
; standard partition initialization, common for all file systems
 
mov edi, eax
mov eax, dword[ebp + PARTITION.FirstSector]
mov dword[edi + XFS.FirstSector], eax
mov eax, dword[ebp + PARTITION.FirstSector + 4]
mov dword[edi + XFS.FirstSector + 4], eax
mov eax, dword[ebp + PARTITION.Length]
mov dword[edi + XFS.Length], eax
mov eax, dword[ebp + PARTITION.Length + 4]
mov dword[edi + XFS.Length + 4], eax
mov eax, [ebp + PARTITION.Disk]
mov [edi + XFS.Disk], eax
mov [edi + XFS.FSUserFunctions], xfs_user_functions
 
; here we initialize only one mutex so far (for the entire partition)
; XFS potentially allows parallel r/w access to several AGs, keep it in mind for SMP times
 
lea ecx, [edi + XFS.Lock]
call mutex_init
 
; read superblock and fill just allocated XFS partition structure
 
mov eax, [ebx + xfs_sb.sb_blocksize]
bswap eax ; XFS is big endian
mov [edi + XFS.blocksize], eax
movzx eax, word[ebx + xfs_sb.sb_sectsize]
xchg al, ah
mov [edi + XFS.sectsize], eax
movzx eax, word[ebx + xfs_sb.sb_versionnum]
xchg al, ah
mov [edi + XFS.versionnum], eax
mov eax, [ebx + xfs_sb.sb_features2]
bswap eax
mov [edi + XFS.features2], eax
movzx eax, word[ebx + xfs_sb.sb_inodesize]
xchg al, ah
mov [edi + XFS.inodesize], eax
movzx eax, word[ebx + xfs_sb.sb_inopblock] ; inodes per block
xchg al, ah
mov [edi + XFS.inopblock], eax
movzx eax, byte[ebx + xfs_sb.sb_blocklog] ; log2 of block size, in bytes
mov [edi + XFS.blocklog], eax
movzx eax, byte[ebx + xfs_sb.sb_sectlog]
mov [edi + XFS.sectlog], eax
movzx eax, byte[ebx + xfs_sb.sb_inodelog]
mov [edi + XFS.inodelog], eax
movzx eax, byte[ebx + xfs_sb.sb_inopblog]
mov [edi + XFS.inopblog], eax
movzx eax, byte[ebx + xfs_sb.sb_dirblklog]
mov [edi + XFS.dirblklog], eax
mov eax, dword[ebx + xfs_sb.sb_rootino + 4] ;
bswap eax ; big
mov dword[edi + XFS.rootino + 0], eax ; endian
mov eax, dword[ebx + xfs_sb.sb_rootino + 0] ; 64bit
bswap eax ; number
mov dword[edi + XFS.rootino + 4], eax ;
 
mov eax, [edi + XFS.blocksize]
mov ecx, [edi + XFS.dirblklog]
shl eax, cl
mov [edi + XFS.dirblocksize], eax ; blocks for files, dirblocks for directories
 
; sector is always smaller than block
; so precalculate shift order to allow faster sector_num->block_num conversion
 
mov ecx, [edi + XFS.blocklog]
sub ecx, [edi + XFS.sectlog]
mov [edi + XFS.blockmsectlog], ecx
 
mov eax, 1
shl eax, cl
mov [edi + XFS.sectpblock], eax
 
; shift order for inode_num->block_num conversion
 
mov eax, [edi + XFS.blocklog]
sub eax, [edi + XFS.inodelog]
mov [edi + XFS.inodetoblocklog], eax
 
mov eax, [ebx + xfs_sb.sb_agblocks]
bswap eax
mov [edi + XFS.agblocks], eax
movzx ecx, byte[ebx + xfs_sb.sb_agblklog]
mov [edi + XFS.agblklog], ecx
 
; get the mask for block numbers
; block numbers are AG relative!
; bitfield length may vary between partitions
 
mov eax, 1
shl eax, cl
dec eax
mov dword[edi + XFS.agblockmask + 0], eax
mov eax, 1
sub ecx, 32
jc @f
shl eax, cl
@@:
dec eax
mov dword[edi + XFS.agblockmask + 4], eax
 
; calculate magic offsets for directories
 
mov ecx, [edi + XFS.blocklog]
mov eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff ; lo
mov edx, XFS_DIR2_LEAF_OFFSET SHR 32 ; hi
shrd eax, edx, cl
mov [edi + XFS.dir2_leaf_offset_blocks], eax
 
mov ecx, [edi + XFS.blocklog]
mov eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff ; lo
mov edx, XFS_DIR2_FREE_OFFSET SHR 32 ; hi
shrd eax, edx, cl
mov [edi + XFS.dir2_free_offset_blocks], eax
 
; mov ecx, [edi + XFS.dirblklog]
; mov eax, [edi + XFS.blocksize]
; shl eax, cl
; mov [edi + XFS.dirblocksize], eax
 
mov eax, [edi + XFS.blocksize]
call malloc
test eax, eax
jz .error
mov [edi + XFS.cur_block], eax
 
; we do need XFS.blocksize bytes for single inode
; minimal file system structure is block, inodes are packed in blocks
 
mov eax, [edi + XFS.blocksize]
call malloc
test eax, eax
jz .error
mov [edi + XFS.cur_inode], eax
 
; temporary inode
; used for browsing directories
 
mov eax, [edi + XFS.blocksize]
call malloc
test eax, eax
jz .error
mov [edi + XFS.tmp_inode], eax
 
; current sector
; only for sector size structures like AGI
; inodes has usually the same size, but never store them here
 
mov eax, [edi + XFS.sectsize]
call malloc
test eax, eax
jz .error
mov [edi + XFS.cur_sect], eax
 
; current directory block
 
mov eax, [edi + XFS.dirblocksize]
call malloc
test eax, eax
jz .error
mov [edi + XFS.cur_dirblock], eax
 
.quit:
mov eax, edi ; return pointer to allocated XFS partition structure
pop edi esi edx ecx ebx
ret
.error:
xor eax, eax
pop edi esi edx ecx ebx
ret
 
 
iglobal
align 4
xfs_user_functions:
dd xfs_free
dd (xfs_user_functions_end - xfs_user_functions - 4) / 4
dd xfs_Read
dd xfs_ReadFolder
dd 0;xfs_Rewrite
dd 0;xfs_Write
dd 0;xfs_SetFileEnd
dd xfs_GetFileInfo
dd 0;xfs_SetFileInfo
dd 0
dd 0;xfs_Delete
dd 0;xfs_CreateFolder
xfs_user_functions_end:
endg
 
 
; lock partition access mutex
proc xfs_lock
;DEBUGF 1,"xfs_lock\n"
lea ecx, [ebp + XFS.Lock]
jmp mutex_lock
endp
 
 
; unlock partition access mutex
proc xfs_unlock
;DEBUGF 1,"xfs_unlock\n"
lea ecx, [ebp + XFS.Lock]
jmp mutex_unlock
endp
 
 
; free all the allocated memory
; called on partition destroy
proc xfs_free
push ebp
xchg ebp, eax
stdcall kernel_free, [ebp + XFS.cur_block]
stdcall kernel_free, [ebp + XFS.cur_inode]
stdcall kernel_free, [ebp + XFS.cur_sect]
stdcall kernel_free, [ebp + XFS.cur_dirblock]
stdcall kernel_free, [ebp + XFS.tmp_inode]
xchg ebp, eax
call free
pop ebp
ret
endp
 
 
;---------------------------------------------------------------
; block number (AG relative)
; eax -- inode_lo
; edx -- inode_hi
; ebx -- buffer
;---------------------------------------------------------------
xfs_read_block:
push ebx esi
 
push edx
push eax
 
; XFS block numbers are AG relative
; they come in bitfield form of concatenated AG and block numbers
; to get absolute block number for fs_read32_sys we should
; 1. extract AG number (using precalculated mask)
; 2. multiply it by the AG size in blocks
; 3. add AG relative block number
 
; 1.
mov ecx, [ebp + XFS.agblklog]
shrd eax, edx, cl
shr edx, cl
; 2.
mul dword[ebp + XFS.agblocks]
pop ecx
pop esi
and ecx, dword[ebp + XFS.agblockmask + 0]
and esi, dword[ebp + XFS.agblockmask + 4]
; 3.
add eax, ecx
adc edx, esi
 
;DEBUGF 1,"read block: 0x%x%x\n",edx,eax
; there is no way to read file system block at once, therefore we
; 1. calculate the number of sectors first
; 2. and then read them in series
 
; 1.
mov ecx, [ebp + XFS.blockmsectlog]
shld edx, eax, cl
shl eax, cl
mov esi, [ebp + XFS.sectpblock]
 
; 2.
.next_sector:
push eax edx
call fs_read32_sys
mov ecx, eax
pop edx eax
test ecx, ecx
jnz .error
add eax, 1 ; be ready to fs_read64_sys
adc edx, 0
add ebx, [ebp + XFS.sectsize] ; update buffer offset
dec esi
jnz .next_sector
 
.quit:
xor eax, eax
pop esi ebx
ret
.error:
mov eax, ecx
pop esi ebx
ret
 
 
;---------------------------------------------------------------
; push buffer
; push startblock_hi
; push startblock_lo
; call xfs_read_dirblock
; test eax, eax
;---------------------------------------------------------------
xfs_read_dirblock:
;mov eax, [esp + 4]
;mov edx, [esp + 8]
;DEBUGF 1,"read dirblock at: %d %d\n",edx,eax
;DEBUGF 1,"dirblklog: %d\n",[ebp + XFS.dirblklog]
push ebx esi
 
mov eax, [esp + 12] ; startblock_lo
mov edx, [esp + 16] ; startblock_hi
mov ebx, [esp + 20] ; buffer
 
; dirblock >= block
; read dirblocks by blocks
 
mov ecx, [ebp + XFS.dirblklog]
mov esi, 1
shl esi, cl
.next_block:
push eax edx
call xfs_read_block
mov ecx, eax
pop edx eax
test ecx, ecx
jnz .error
add eax, 1 ; be ready to fs_read64_sys
adc edx, 0
add ebx, [ebp + XFS.blocksize]
dec esi
jnz .next_block
 
.quit:
xor eax, eax
pop esi ebx
ret 12
.error:
mov eax, ecx
pop esi ebx
ret 12
 
 
;---------------------------------------------------------------
; push buffer
; push inode_hi
; push inode_lo
; call xfs_read_inode
; test eax, eax
;---------------------------------------------------------------
xfs_read_inode:
;DEBUGF 1,"reading inode: 0x%x%x\n",[esp+8],[esp+4]
push ebx
mov eax, [esp + 8] ; inode_lo
mov edx, [esp + 12] ; inode_hi
mov ebx, [esp + 16] ; buffer
 
; inodes are packed into blocks
; 1. calculate block number
; 2. read the block
; 3. add inode offset to block base address
 
; 1.
mov ecx, [ebp + XFS.inodetoblocklog]
shrd eax, edx, cl
shr edx, cl
; 2.
call xfs_read_block
test eax, eax
jnz .error
 
; note that inode numbers should be first extracted from bitfields using mask
 
mov eax, [esp + 8]
mov edx, 1
mov ecx, [ebp + XFS.inopblog]
shl edx, cl
dec edx ; get inode number mask
and eax, edx ; apply mask
mov ecx, [ebp + XFS.inodelog]
shl eax, cl
add ebx, eax
 
cmp word[ebx], XFS_DINODE_MAGIC ; test signature
jne .error
.quit:
xor eax, eax
mov edx, ebx
pop ebx
ret 12
.error:
movi eax, ERROR_FS_FAIL
mov edx, ebx
pop ebx
ret 12
 
 
;----------------------------------------------------------------
; push encoding ; ASCII / UNICODE
; push src ; inode
; push dst ; bdfe
; push entries_to_read
; push start_number ; from 0
;----------------------------------------------------------------
xfs_dir_get_bdfes:
DEBUGF 1,"xfs_dir_get_bdfes: %d entries from %d\n",[esp+8],[esp+4]
sub esp, 4 ; local vars
push ecx edx esi edi
 
mov ebx, [esp + 36] ; src
mov edx, [esp + 32] ; dst
mov ecx, [esp + 24] ; start_number
 
; define directory ondisk format and jump to corresponding label
 
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL
jne .not_shortdir
jmp .shortdir
.not_shortdir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_blockdir
mov eax, [ebx + xfs_inode.di_core.di_nextents]
bswap eax
cmp eax, 1
jne .not_blockdir
jmp .blockdir
.not_blockdir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_leafdir
mov eax, [ebx + xfs_inode.di_core.di_nextents]
bswap eax
cmp eax, 4
ja .not_leafdir
jmp .leafdir
.not_leafdir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_nodedir
jmp .nodedir
.not_nodedir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jne .not_btreedir
jmp .btreedir
.not_btreedir:
movi eax, ERROR_FS_FAIL
jmp .error
 
; short form directory (all the data fits into inode)
.shortdir:
;DEBUGF 1,"shortdir\n",
movzx eax, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count]
test al, al ; is count zero?
jnz @f ; if not, use it (i8count must be zero then)
shr eax, 8 ; use i8count
@@:
add eax, 1 ; '..' and '.' are implicit
mov dword[edx + 0], 1 ; version
mov [edx + 8], eax ; total entries
sub eax, [esp + 24] ; start number
cmp eax, [esp + 28] ; entries to read
jbe @f
mov eax, [esp + 28]
@@:
mov [esp + 28], eax
mov [edx + 4], eax ; number of actually read entries
mov [ebp + XFS.entries_read], eax
 
; inode numbers are often saved as 4 bytes (iff they fit)
; compute the length of inode numbers
 
mov eax, 4 ; 4 by default
cmp byte[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.i8count], 0
je @f
add eax, eax ; 4+4=8, iff i8count != 0
@@:
mov dword[edx + 12], 0 ; reserved
mov dword[edx + 16], 0 ;
mov dword[edx + 20], 0 ;
mov dword[edx + 24], 0 ;
mov dword[edx + 28], 0 ;
add edx, 32
lea esi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax]
dec ecx
js .shortdir.fill
 
; skip some entries if the first entry to read is not 0
 
.shortdir.skip:
test ecx, ecx
jz .shortdir.skipped
movzx edi, byte[esi + xfs_dir2_sf_entry.namelen]
lea esi, [esi + xfs_dir2_sf_entry.name + edi]
add esi, eax
dec ecx
jnz .shortdir.skip
mov ecx, [esp + 28] ; entries to read
jmp .shortdir.skipped
.shortdir.fill:
mov ecx, [esp + 28] ; total number
test ecx, ecx
jz .quit
push ecx
;DEBUGF 1,"ecx: %d\n",ecx
lea edi, [edx + 40] ; get file name offset
;DEBUGF 1,"filename: ..\n"
mov dword[edi], '..'
mov edi, edx
push eax ebx edx esi
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent]
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
; test eax, eax
; jnz .error
stdcall xfs_get_inode_info, edx, edi
test eax, eax
pop esi edx ebx eax
jnz .error
mov ecx, [esp + 44] ; file name encding
mov [edx + 4], ecx
add edx, 304 ; ASCII only for now
pop ecx
dec ecx
jz .quit
 
; push ecx
; lea edi, [edx + 40]
;DEBUGF 1,"filename: .\n"
; mov dword[edi], '.'
; mov edi, edx
; push eax edx
; stdcall xfs_get_inode_info, [ebp + XFS.cur_inode], edi
; test eax, eax
; pop edx eax
; jnz .error
; mov ecx, [esp + 44]
; mov [edx + 4], ecx
; add edx, 304 ; ASCII only for now
; pop ecx
; dec ecx
; jz .quit
 
; we skipped some entries
; now we fill min(required, present) number of bdfe's
 
.shortdir.skipped:
;DEBUGF 1,"ecx: %d\n",ecx
push ecx
movzx ecx, byte[esi + xfs_dir2_sf_entry.namelen]
add esi, xfs_dir2_sf_entry.name
lea edi, [edx + 40] ; bdfe offset of file name
;DEBUGF 1,"filename: |%s|\n",esi
rep movsb
mov word[edi], 0 ; terminator (ASCIIZ)
 
push eax ebx ecx edx esi
; push edx ; for xfs_get_inode_info
mov edi, edx
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [esi + 4], [esi]
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
; test eax, eax
; jnz .error
stdcall xfs_get_inode_info, edx, edi
test eax, eax
pop esi edx ecx ebx eax
jnz .error
mov ecx, [esp + 44] ; file name encoding
mov [edx + 4], ecx
 
add edx, 304 ; ASCII only for now
add esi, eax
pop ecx
dec ecx
jnz .shortdir.skipped
jmp .quit
 
.blockdir:
;DEBUGF 1,"blockdir\n"
push edx
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
stdcall xfs_extent_unpack, eax
;DEBUGF 1,"extent.br_startoff : 0x%x%x\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0]
;DEBUGF 1,"extent.br_startblock: 0x%x%x\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0]
;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount]
;DEBUGF 1,"extent.br_state : %d\n",[ebp+XFS.extent.br_state]
stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock]
test eax, eax
pop edx
jnz .error
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
mov ebx, [ebp + XFS.cur_dirblock]
mov dword[edx + 0], 1 ; version
mov eax, [ebp + XFS.dirblocksize]
mov ecx, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.stale]
mov eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count]
bswap ecx
bswap eax
sub eax, ecx ; actual number of entries = count - stale
mov [edx + 8], eax ; total entries
;DEBUGF 1,"total entries: %d\n",eax
sub eax, [esp + 24] ; start number
cmp eax, [esp + 28] ; entries to read
jbe @f
mov eax, [esp + 28]
@@:
mov [esp + 28], eax
mov [edx + 4], eax ; number of actually read entries
mov [ebp + XFS.entries_read], eax
;DEBUGF 1,"actually read entries: %d\n",eax
mov dword[edx + 12], 0 ; reserved
mov dword[edx + 16], 0 ;
mov dword[edx + 20], 0 ;
mov dword[edx + 24], 0 ;
mov dword[edx + 28], 0 ;
add ebx, xfs_dir2_block.u
 
mov ecx, [esp + 24] ; start entry number
; also means how many to skip
test ecx, ecx
jz .blockdir.skipped
.blockdir.skip:
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
jne @f
movzx eax, word[ebx + xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .blockdir.skip
@@:
movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen]
lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 bytes for 'tag'
add ebx, 7 ; align on 8 bytes
and ebx, not 7
dec ecx
jnz .blockdir.skip
.blockdir.skipped:
mov ecx, [edx + 4] ; actually read entries
test ecx, ecx
jz .quit
add edx, 32 ; set edx to the first bdfe
.blockdir.next_entry:
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_NULL
jne @f
movzx eax, word[ebx + xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .blockdir.next_entry
@@:
push ecx
push eax ebx ecx edx esi
mov edi, edx
mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
bswap edx
bswap eax
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
stdcall xfs_get_inode_info, edx, edi
test eax, eax
pop esi edx ecx ebx eax
jnz .error
mov ecx, [esp + 44]
mov [edx + 4], ecx
lea edi, [edx + 40]
movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
lea esi, [ebx + xfs_dir2_data_union.xentry.name]
;DEBUGF 1,"filename: |%s|\n",esi
rep movsb
; call utf8_to_cp866
mov word[edi], 0 ; terminator
lea ebx, [esi + 2] ; skip 'tag'
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes
and ebx, not 7
add edx, 304
pop ecx
dec ecx
jnz .blockdir.next_entry
jmp .quit
 
.leafdir:
;DEBUGF 1,"readdir: leaf\n"
mov [ebp + XFS.cur_inode_save], ebx
push ebx ecx edx
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, 0xffffffff, 0xffffffff
mov ecx, eax
and ecx, edx
inc ecx
pop edx ecx ebx
jz .error
 
mov eax, [ebp + XFS.cur_dirblock]
movzx ecx, word[eax + xfs_dir2_leaf.hdr.stale]
movzx eax, word[eax + xfs_dir2_leaf.hdr.count]
xchg cl, ch
xchg al, ah
sub eax, ecx
;DEBUGF 1,"total count: %d\n",eax
 
mov dword[edx + 0], 1 ; version
mov [edx + 8], eax ; total entries
sub eax, [esp + 24] ; start number
cmp eax, [esp + 28] ; entries to read
jbe @f
mov eax, [esp + 28]
@@:
mov [esp + 28], eax
mov [edx + 4], eax ; number of actually read entries
 
mov dword[edx + 12], 0 ; reserved
mov dword[edx + 16], 0 ;
mov dword[edx + 20], 0 ;
mov dword[edx + 24], 0 ;
mov dword[edx + 28], 0 ;
 
mov eax, [ebp + XFS.cur_dirblock]
add eax, [ebp + XFS.dirblocksize]
mov [ebp + XFS.max_dirblockaddr], eax
mov dword[ebp + XFS.next_block_num + 0], 0
mov dword[ebp + XFS.next_block_num + 4], 0
 
mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately
mov ecx, [esp + 24] ; start number
test ecx, ecx
jz .leafdir.skipped
.leafdir.skip:
cmp ebx, [ebp + XFS.max_dirblockaddr]
jne @f
push ecx edx
mov ebx, [ebp + XFS.cur_inode_save]
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
mov ecx, eax
and ecx, edx
inc ecx
jz .error
add eax, 1
adc edx, 0
mov dword[ebp + XFS.next_block_num + 0], eax
mov dword[ebp + XFS.next_block_num + 4], edx
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, sizeof.xfs_dir2_data_hdr
pop edx ecx
@@:
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
jne @f
movzx eax, word[ebx + xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .leafdir.skip
@@:
movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen]
lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 for 'tag'
add ebx, 7
and ebx, not 7
dec ecx
jnz .leafdir.skip
.leafdir.skipped:
mov [ebp + XFS.entries_read], 0
mov ecx, [edx + 4] ; actually read entries
test ecx, ecx
jz .quit
add edx, 32 ; first bdfe entry
.leafdir.next_entry:
;DEBUGF 1,"next_extry\n"
cmp ebx, [ebp + XFS.max_dirblockaddr]
jne .leafdir.process_current_block
push ecx edx
mov ebx, [ebp + XFS.cur_inode_save]
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
mov ecx, eax
and ecx, edx
inc ecx
jnz @f
pop edx ecx
jmp .quit
@@:
add eax, 1
adc edx, 0
mov dword[ebp + XFS.next_block_num + 0], eax
mov dword[ebp + XFS.next_block_num + 4], edx
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, sizeof.xfs_dir2_data_hdr
pop edx ecx
.leafdir.process_current_block:
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
jne @f
movzx eax, word[ebx + xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .leafdir.next_entry
@@:
push eax ebx ecx edx esi
mov edi, edx
mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
bswap edx
bswap eax
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
stdcall xfs_get_inode_info, edx, edi
test eax, eax
pop esi edx ecx ebx eax
jnz .error
push ecx
mov ecx, [esp + 44]
mov [edx + 4], ecx
lea edi, [edx + 40]
movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
lea esi, [ebx + xfs_dir2_data_union.xentry.name]
;DEBUGF 1,"filename: |%s|\n",esi
rep movsb
pop ecx
mov word[edi], 0
lea ebx, [esi + 2] ; skip 'tag'
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes
and ebx, not 7
add edx, 304 ; ASCII only for now
inc [ebp + XFS.entries_read]
dec ecx
jnz .leafdir.next_entry
jmp .quit
 
.nodedir:
;DEBUGF 1,"readdir: node\n"
push edx
mov [ebp + XFS.cur_inode_save], ebx
mov [ebp + XFS.entries_read], 0
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks]
pop edx
test eax, eax
jnz .error
mov eax, [ebp + XFS.entries_read]
mov [ebp + XFS.entries_read], 0
;DEBUGF 1,"numfiles: %d\n",eax
mov dword[edx + 0], 1 ; version
mov [edx + 8], eax ; total entries
sub eax, [esp + 24] ; start number
cmp eax, [esp + 28] ; entries to read
jbe @f
mov eax, [esp + 28]
@@:
mov [esp + 28], eax
mov [edx + 4], eax ; number of actually read entries
 
mov dword[edx + 12], 0 ; reserved
mov dword[edx + 16], 0 ;
mov dword[edx + 20], 0 ;
mov dword[edx + 24], 0 ;
mov dword[edx + 28], 0 ;
 
mov eax, [ebp + XFS.cur_dirblock]
add eax, [ebp + XFS.dirblocksize]
mov [ebp + XFS.max_dirblockaddr], eax
mov dword[ebp + XFS.next_block_num + 0], 0
mov dword[ebp + XFS.next_block_num + 4], 0
 
mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately
mov ecx, [esp + 24] ; start number
test ecx, ecx
jz .leafdir.skipped
jmp .leafdir.skip
 
.btreedir:
;DEBUGF 1,"readdir: btree\n"
mov [ebp + XFS.cur_inode_save], ebx
push ebx edx
mov eax, [ebx + xfs_inode.di_core.di_nextents]
bswap eax
mov [ebp + XFS.ro_nextents], eax
mov eax, [ebp + XFS.inodesize]
sub eax, xfs_inode.di_u
sub eax, sizeof.xfs_bmdr_block
shr eax, 4
;DEBUGF 1,"maxnumresc: %d\n",eax
mov edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0]
mov eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4]
bswap eax
bswap edx
mov ebx, [ebp + XFS.cur_block]
;DEBUGF 1,"read_block: %x %x ",edx,eax
stdcall xfs_read_block
pop edx ebx
test eax, eax
jnz .error
;DEBUGF 1,"ok\n"
 
mov ebx, [ebp + XFS.cur_block]
push edx
mov [ebp + XFS.entries_read], 0
lea eax, [ebx + sizeof.xfs_bmbt_block]
mov edx, [ebp + XFS.ro_nextents]
stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks]
pop edx
test eax, eax
jnz .error
mov eax, [ebp + XFS.entries_read]
mov [ebp + XFS.entries_read], 0
;DEBUGF 1,"numfiles: %d\n",eax
 
mov dword[edx + 0], 1 ; version
mov [edx + 8], eax ; total entries
sub eax, [esp + 24] ; start number
cmp eax, [esp + 28] ; entries to read
jbe @f
mov eax, [esp + 28]
@@:
mov [esp + 28], eax
mov [edx + 4], eax ; number of actually read entries
 
mov dword[edx + 12], 0
mov dword[edx + 16], 0
mov dword[edx + 20], 0
mov dword[edx + 24], 0
mov dword[edx + 28], 0
 
mov eax, [ebp + XFS.cur_dirblock] ; fsblock?
add eax, [ebp + XFS.dirblocksize]
mov [ebp + XFS.max_dirblockaddr], eax
mov dword[ebp + XFS.next_block_num + 0], 0
mov dword[ebp + XFS.next_block_num + 4], 0
 
mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately
mov ecx, [esp + 24] ; start number
test ecx, ecx
jz .btreedir.skipped
; jmp .btreedir.skip
.btreedir.skip:
cmp ebx, [ebp + XFS.max_dirblockaddr]
jne @f
push ecx edx
mov ebx, [ebp + XFS.cur_block]
lea eax, [ebx + sizeof.xfs_bmbt_block]
mov edx, [ebp + XFS.ro_nextents]
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
mov ecx, eax
and ecx, edx
inc ecx
jz .error
add eax, 1
adc edx, 0
mov dword[ebp + XFS.next_block_num + 0], eax
mov dword[ebp + XFS.next_block_num + 4], edx
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, sizeof.xfs_dir2_data_hdr
pop edx ecx
@@:
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
jne @f
movzx eax, word[ebx + xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .btreedir.skip
@@:
movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen]
lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 for 'tag'
add ebx, 7
and ebx, not 7
dec ecx
jnz .btreedir.skip
.btreedir.skipped:
mov [ebp + XFS.entries_read], 0
mov ecx, [edx + 4] ; actually read entries
test ecx, ecx
jz .quit
add edx, 32
.btreedir.next_entry:
;mov eax, [ebp + XFS.entries_read]
;DEBUGF 1,"next_extry: %d\n",eax
cmp ebx, [ebp + XFS.max_dirblockaddr]
jne .btreedir.process_current_block
push ecx edx
mov ebx, [ebp + XFS.cur_block]
lea eax, [ebx + sizeof.xfs_bmbt_block]
mov edx, [ebp + XFS.ro_nextents]
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
mov ecx, eax
and ecx, edx
inc ecx
jnz @f
pop edx ecx
jmp .quit
@@:
add eax, 1
adc edx, 0
mov dword[ebp + XFS.next_block_num + 0], eax
mov dword[ebp + XFS.next_block_num + 4], edx
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, sizeof.xfs_dir2_data_hdr
pop edx ecx
.btreedir.process_current_block:
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
jne @f
movzx eax, word[ebx + xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .btreedir.next_entry
@@:
push eax ebx ecx edx esi
mov edi, edx
mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
bswap edx
bswap eax
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
stdcall xfs_get_inode_info, edx, edi
test eax, eax
pop esi edx ecx ebx eax
jnz .error
push ecx
mov ecx, [esp + 44]
mov [edx + 4], ecx
lea edi, [edx + 40]
movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
lea esi, [ebx + xfs_dir2_data_union.xentry.name]
;DEBUGF 1,"filename: |%s|\n",esi
rep movsb
pop ecx
mov word[edi], 0
lea ebx, [esi + 2] ; skip 'tag'
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes
and ebx, not 7
add edx, 304
inc [ebp + XFS.entries_read]
dec ecx
jnz .btreedir.next_entry
jmp .quit
 
 
.quit:
pop edi esi edx ecx
add esp, 4 ; pop vars
xor eax, eax
; mov ebx, [esp + 8]
mov ebx, [ebp + XFS.entries_read]
DEBUGF 1,"xfs_dir_get_bdfes done: %d\n",ebx
ret 20
.error:
pop edi esi edx ecx
add esp, 4 ; pop vars
mov eax, ERROR_FS_FAIL
movi ebx, -1
ret 20
 
 
;----------------------------------------------------------------
; push inode_hi
; push inode_lo
; push name
;----------------------------------------------------------------
xfs_get_inode_short:
; this function searches for the file in _current_ dir
; it is called recursively for all the subdirs /path/to/my/file
 
;DEBUGF 1,"xfs_get_inode_short: %s\n",[esp+4]
mov esi, [esp + 4] ; name
movzx eax, word[esi]
cmp eax, '.' ; current dir; it is already read, just return
je .quit
cmp eax, './' ; same thing
je .quit
 
; read inode
 
mov eax, [esp + 8] ; inode_lo
mov edx, [esp + 12] ; inode_hi
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
 
; find file name in directory
; switch directory ondisk format
 
mov ebx, edx
mov [ebp + XFS.cur_inode_save], ebx
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL
jne .not_shortdir
;DEBUGF 1,"dir: shortdir\n"
jmp .shortdir
.not_shortdir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_blockdir
mov eax, [ebx + xfs_inode.di_core.di_nextents]
bswap eax
cmp eax, 1
jne .not_blockdir
jmp .blockdir
.not_blockdir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_leafdir
mov eax, [ebx + xfs_inode.di_core.di_nextents]
bswap eax
cmp eax, 4
ja .not_leafdir
jmp .leafdir
.not_leafdir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_nodedir
jmp .nodedir
.not_nodedir:
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jne .not_btreedir
jmp .btreedir
.not_btreedir:
DEBUGF 1,"NOT IMPLEMENTED: DIR FORMAT\n"
jmp .error
 
.shortdir:
.shortdir.check_parent:
; parent inode number in shortform directories is always implicit, check this case
mov eax, [esi]
and eax, 0x00ffffff
cmp eax, '..'
je .shortdir.parent2
cmp eax, '../'
je .shortdir.parent3
jmp .shortdir.common
.shortdir.parent3:
inc esi
.shortdir.parent2:
add esi, 2
add ebx, xfs_inode.di_u
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_dir2_sf_hdr.count], dword[ebx + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_dir2_sf_hdr.parent]
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
jmp .quit
 
; not a parent inode?
; search in the list, all the other files are stored uniformly
 
.shortdir.common:
mov eax, 4
movzx edx, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] ; read count (byte) and i8count (byte) at once
test dl, dl ; is count zero?
jnz @f
shr edx, 8 ; use i8count
add eax, eax ; inode_num size
@@:
lea edi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax]
 
.next_name:
movzx ecx, byte[edi + xfs_dir2_sf_entry.namelen]
add edi, xfs_dir2_sf_entry.name
mov esi, [esp + 4]
;DEBUGF 1,"esi: %s\n",esi
;DEBUGF 1,"edi: %s\n",edi
repe cmpsb
jne @f
cmp byte[esi], 0 ; HINT: use adc here?
je .found
cmp byte[esi], '/'
je .found_inc
@@:
add edi, ecx
add edi, eax
dec edx
jnz .next_name
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
.found_inc: ; increment esi to skip '/' symbol
; this means esi always points to valid file name or zero terminator byte
inc esi
.found:
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [edi + 4], [edi]
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
jmp .quit
 
.blockdir:
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
stdcall xfs_extent_unpack, eax
stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock]
test eax, eax
jnz .error
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
mov ebx, [ebp + XFS.cur_dirblock]
mov eax, [ebp + XFS.dirblocksize]
mov eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count]
; note that we don't subtract xfs_dir2_block_tail.stale here,
; since we need the number of leaf entries rather than file number
bswap eax
add ebx, [ebp + XFS.dirblocksize]
; mov ecx, sizeof.xfs_dir2_leaf_entry
imul ecx, eax, sizeof.xfs_dir2_leaf_entry
sub ebx, sizeof.xfs_dir2_block_tail
sub ebx, ecx
shr ecx, 3
push ecx ; for xfs_get_inode_by_hash
push ebx ; for xfs_get_inode_by_hash
 
mov edi, esi
xor eax, eax
mov ecx, 4096 ; MAX_PATH_LEN
repne scasb
movi eax, ERROR_FS_FAIL
jne .error
neg ecx
add ecx, 4096 ; MAX_PATH_LEN
dec ecx
mov edx, ecx
;DEBUGF 1,"strlen total : %d\n",edx
mov edi, esi
mov eax, '/'
mov ecx, edx
repne scasb
jne @f
inc ecx
@@:
neg ecx
add ecx, edx
;DEBUGF 1,"strlen current: %d\n",ecx
stdcall xfs_hashname, esi, ecx
add esi, ecx
cmp byte[esi], '/'
jne @f
inc esi
@@:
;DEBUGF 1,"hashed: 0x%x\n",eax
; bswap eax
stdcall xfs_get_addr_by_hash
bswap eax
;DEBUGF 1,"got address: 0x%x\n",eax
cmp eax, -1
jne @f
movi eax, ERROR_FILE_NOT_FOUND
mov ebx, -1
jmp .error
@@:
shl eax, 3
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, eax
mov edx, [ebx + 0]
mov eax, [ebx + 4]
bswap edx
bswap eax
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
jmp .quit
 
.leafdir:
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, -1, -1
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
mov ecx, eax
and ecx, edx
inc ecx
jz .error
 
mov ebx, [ebp + XFS.cur_dirblock]
movzx eax, [ebx + xfs_dir2_leaf.hdr.count]
; note that we don't subtract xfs_dir2_leaf.hdr.stale here,
; since we need the number of leaf entries rather than file number
xchg al, ah
add ebx, xfs_dir2_leaf.ents
; imul ecx, eax, sizeof.xfs_dir2_leaf_entry
; shr ecx, 3
push eax ; for xfs_get_addr_by_hash: len
push ebx ; for xfs_get_addr_by_hash: base
 
mov edi, esi
xor eax, eax
mov ecx, 4096 ; MAX_PATH_LEN
repne scasb
movi eax, ERROR_FS_FAIL
jne .error
neg ecx
add ecx, 4096
dec ecx
mov edx, ecx
;DEBUGF 1,"strlen total : %d\n",edx
mov edi, esi
mov eax, '/'
mov ecx, edx
repne scasb
jne @f
inc ecx
@@:
neg ecx
add ecx, edx
;DEBUGF 1,"strlen current: %d\n",ecx
stdcall xfs_hashname, esi, ecx
add esi, ecx
cmp byte[esi], '/'
jne @f
inc esi
@@:
;DEBUGF 1,"hashed: 0x%x\n",eax
stdcall xfs_get_addr_by_hash
bswap eax
;DEBUGF 1,"got address: 0x%x\n",eax
cmp eax, -1
jne @f
movi eax, ERROR_FILE_NOT_FOUND
mov ebx, -1
jmp .error
@@:
 
mov ebx, [ebp + XFS.cur_inode_save]
push esi edi
xor edi, edi
mov esi, eax
shld edi, esi, 3 ; get offset
shl esi, 3 ; 2^3 = 8 byte align
mov edx, esi
mov ecx, [ebp + XFS.dirblklog]
add ecx, [ebp + XFS.blocklog]
mov eax, 1
shl eax, cl
dec eax
and edx, eax
push edx
shrd esi, edi, cl
shr edi, cl
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
pop edx
pop edi esi
mov ecx, eax
and ecx, edx
inc ecx
jz .error
 
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, edx
mov edx, [ebx + 0]
mov eax, [ebx + 4]
bswap edx
bswap eax
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
jmp .quit
 
.nodedir:
;DEBUGF 1,"lookupdir: node\n"
mov [ebp + XFS.cur_inode_save], ebx
 
mov edi, esi
xor eax, eax
mov ecx, 4096 ; MAX_PATH_LEN
repne scasb
movi eax, ERROR_FS_FAIL
jne .error
neg ecx
add ecx, 4096 ; MAX_PATH_LEN
dec ecx
mov edx, ecx
;DEBUGF 1,"strlen total : %d\n",edx
mov edi, esi
mov eax, '/'
mov ecx, edx
repne scasb
jne @f
inc ecx
@@:
neg ecx
add ecx, edx
;DEBUGF 1,"strlen current: %d\n",ecx
stdcall xfs_hashname, esi, ecx
add esi, ecx
cmp byte[esi], '/'
jne @f
inc esi
@@:
;DEBUGF 1,"hashed: 0x%x\n",eax
push edi edx
mov edi, eax
mov [ebp + XFS.entries_read], 0
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi
pop edx edi
test eax, eax
jnz .error
bswap ecx
;DEBUGF 1,"got address: 0x%x\n",ecx
 
mov ebx, [ebp + XFS.cur_inode_save]
push esi edi
xor edi, edi
mov esi, ecx
shld edi, esi, 3 ; get offset
shl esi, 3 ; 8 byte align
mov edx, esi
mov ecx, [ebp + XFS.dirblklog]
add ecx, [ebp + XFS.blocklog]
mov eax, 1
shl eax, cl
dec eax
and edx, eax
push edx
shrd esi, edi, cl
shr edi, cl
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
mov edx, [ebx + xfs_inode.di_core.di_nextents]
bswap edx
stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
pop edx
pop edi esi
mov ecx, eax
and ecx, edx
inc ecx
jz .error
 
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, edx
mov edx, [ebx + 0]
mov eax, [ebx + 4]
bswap edx
bswap eax
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
jmp .quit
 
.btreedir:
DEBUGF 1,"lookupdir: btree\n"
mov [ebp + XFS.cur_inode_save], ebx
 
push ebx edx
mov eax, [ebx + xfs_inode.di_core.di_nextents]
bswap eax
mov [ebp + XFS.ro_nextents], eax
mov eax, [ebp + XFS.inodesize]
sub eax, xfs_inode.di_u
sub eax, sizeof.xfs_bmdr_block
shr eax, 4 ; FIXME forkoff
;DEBUGF 1,"maxnumresc: %d\n",eax
mov edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0]
mov eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4]
bswap eax
bswap edx
mov ebx, [ebp + XFS.cur_block]
;DEBUGF 1,"read_block: %x %x ",edx,eax
stdcall xfs_read_block
pop edx ebx
test eax, eax
jnz .error
;DEBUGF 1,"ok\n"
mov ebx, [ebp + XFS.cur_block]
 
mov edi, esi
xor eax, eax
mov ecx, 4096 ; MAX_PATH_LEN
repne scasb
movi eax, ERROR_FS_FAIL
jne .error
neg ecx
add ecx, 4096
dec ecx
mov edx, ecx
DEBUGF 1,"strlen total : %d\n",edx
mov edi, esi
mov eax, '/'
mov ecx, edx
repne scasb
jne @f
inc ecx
@@:
neg ecx
add ecx, edx
DEBUGF 1,"strlen current: %d\n",ecx
stdcall xfs_hashname, esi, ecx
add esi, ecx
cmp byte[esi], '/'
jne @f
inc esi
@@:
DEBUGF 1,"hashed: 0x%x\n",eax
push edi edx
mov edi, eax
mov [ebp + XFS.entries_read], 0
lea eax, [ebx + sizeof.xfs_bmbt_block]
mov edx, [ebp + XFS.ro_nextents]
;push eax
;mov eax, [ebp + XFS.dir2_leaf_offset_blocks]
;DEBUGF 1,": 0x%x %d\n",eax,eax
;pop eax
stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi
pop edx edi
test eax, eax
jnz .error
bswap ecx
DEBUGF 1,"got address: 0x%x\n",ecx
 
mov ebx, [ebp + XFS.cur_block]
push esi edi
xor edi, edi
mov esi, ecx
shld edi, esi, 3 ; get offset
shl esi, 3
mov edx, esi
mov ecx, [ebp + XFS.dirblklog]
add ecx, [ebp + XFS.blocklog]
mov eax, 1
shl eax, cl
dec eax
and edx, eax
push edx
shrd esi, edi, cl
shr edi, cl
lea eax, [ebx + sizeof.xfs_bmbt_block]
mov edx, [ebp + XFS.ro_nextents]
stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
pop edx
pop edi esi
mov ecx, eax
and ecx, edx
inc ecx
jz .error
 
mov ebx, [ebp + XFS.cur_dirblock]
add ebx, edx
mov edx, [ebx + 0]
mov eax, [ebx + 4]
bswap edx
bswap eax
DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
jmp .quit
 
.quit:
ret 12
.error:
xor eax, eax
mov edx, eax
ret 12
 
 
;----------------------------------------------------------------
; push name
; call xfs_get_inode
; test eax, eax
;----------------------------------------------------------------
xfs_get_inode:
; call xfs_get_inode_short until file is found / error returned
 
;DEBUGF 1,"getting inode of: %s\n",[esp+4]
push ebx esi edi
 
; start from the root inode
 
mov edx, dword[ebp + XFS.rootino + 4] ; hi
mov eax, dword[ebp + XFS.rootino + 0] ; lo
mov esi, [esp + 16] ; name
 
.next_dir:
cmp byte[esi], 0
je .found
 
;DEBUGF 1,"next_level: |%s|\n",esi
stdcall xfs_get_inode_short, esi, eax, edx
test edx, edx
jnz @f
test eax, eax
jz .error
@@:
jmp .next_dir ; file name found, go to next directory level
 
.found:
 
.quit:
pop edi esi ebx
ret 4
.error:
pop edi esi ebx
xor eax, eax
mov edx, eax
ret 4
 
 
;----------------------------------------------------------------
; xfs_ReadFolder - XFS implementation of reading a folder
; in: ebp = pointer to XFS structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
xfs_ReadFolder:
 
; to read folder
; 1. lock partition
; 2. find inode number
; 3. read this inode
; 4. get bdfe's
; 5. unlock partition
 
; 1.
call xfs_lock
push ecx edx esi edi
 
; 2.
push ebx esi edi
add esi, [esp + 32] ; directory name
;DEBUGF 1,"xfs_ReadFolder: |%s|\n",esi
stdcall xfs_get_inode, esi
pop edi esi ebx
mov ecx, edx
or ecx, eax
jnz @f
movi eax, ERROR_FILE_NOT_FOUND
@@:
 
; 3.
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
 
; 4.
mov eax, [ebx + 8] ; encoding
and eax, 1
stdcall xfs_dir_get_bdfes, [ebx + 4], [ebx + 12], [ebx + 16], edx, eax
test eax, eax
jnz .error
 
.quit:
;DEBUGF 1,"\n\n"
pop edi esi edx ecx
; 5.
call xfs_unlock
xor eax, eax
ret
.error:
;DEBUGF 1,"\n\n"
pop edi esi edx ecx
push eax
call xfs_unlock
pop eax
ret
 
 
;----------------------------------------------------------------
; push inode_num_hi
; push inode_num_lo
; push [count]
; call xfs_get_inode_number_sf
;----------------------------------------------------------------
xfs_get_inode_number_sf:
 
; inode numbers in short form directories may be 4 or 8 bytes long
; determine the length in run time and read inode number at given address
 
cmp byte[esp + 4 + xfs_dir2_sf_hdr.i8count], 0 ; i8count == 0 means 4 byte per inode number
je .i4bytes
.i8bytes:
mov edx, [esp + 12] ; hi
mov eax, [esp + 8] ; lo
bswap edx ; big endian
bswap eax
ret 12
.i4bytes:
xor edx, edx ; no hi
mov eax, [esp + 12] ; hi = lo
bswap eax ; big endian
ret 12
 
 
;----------------------------------------------------------------
; push dest
; push src
; call xfs_get_inode_info
;----------------------------------------------------------------
xfs_get_inode_info:
 
; get access time and other file properties
; useful for browsing directories
; called for each dir entry
 
;DEBUGF 1,"get_inode_info\n"
xor eax, eax
mov edx, [esp + 4]
movzx ecx, word[edx + xfs_inode.di_core.di_mode]
xchg cl, ch
;DEBUGF 1,"di_mode: %x\n",ecx
test ecx, S_IFDIR ; directory?
jz @f
mov eax, 0x10 ; set directory flag
@@:
 
mov edi, [esp + 8]
mov [edi + 0], eax
mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
bswap eax
mov dword[edi + 36], eax ; file size hi
;DEBUGF 1,"file_size hi: %d\n",eax
mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
bswap eax
mov dword[edi + 32], eax ; file size lo
;DEBUGF 1,"file_size lo: %d\n",eax
 
add edi, 8
mov eax, [edx + xfs_inode.di_core.di_ctime.t_sec]
bswap eax
push edx
xor edx, edx
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600
adc edx, 2
call ntfs_datetime_to_bdfe.sec
pop edx
 
mov eax, [edx + xfs_inode.di_core.di_atime.t_sec]
bswap eax
push edx
xor edx, edx
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600
adc edx, 2
call ntfs_datetime_to_bdfe.sec
pop edx
 
mov eax, [edx + xfs_inode.di_core.di_mtime.t_sec]
bswap eax
push edx
xor edx, edx
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600
adc edx, 2
call ntfs_datetime_to_bdfe.sec
pop edx
 
.quit:
xor eax, eax
ret 8
.error:
movi eax, ERROR_FS_FAIL
ret 8
 
 
;----------------------------------------------------------------
; push extent_data
; call xfs_extent_unpack
;----------------------------------------------------------------
xfs_extent_unpack:
 
; extents come as packet 128bit bitfields
; lets unpack them to access internal fields
; write result to the XFS.extent structure
 
push eax ebx ecx edx
mov ebx, [esp + 20]
 
xor eax, eax
mov edx, [ebx + 0]
bswap edx
test edx, 0x80000000 ; mask, see documentation
setnz al
mov [ebp + XFS.extent.br_state], eax
 
and edx, 0x7fffffff ; mask
mov eax, [ebx + 4]
bswap eax
shrd eax, edx, 9
shr edx, 9
mov dword[ebp + XFS.extent.br_startoff + 0], eax
mov dword[ebp + XFS.extent.br_startoff + 4], edx
 
mov edx, [ebx + 4]
mov eax, [ebx + 8]
mov ecx, [ebx + 12]
bswap edx
bswap eax
bswap ecx
and edx, 0x000001ff ; mask
shrd ecx, eax, 21
shrd eax, edx, 21
mov dword[ebp + XFS.extent.br_startblock + 0], ecx
mov dword[ebp + XFS.extent.br_startblock + 4], eax
 
mov eax, [ebx + 12]
bswap eax
and eax, 0x001fffff ; mask
mov [ebp + XFS.extent.br_blockcount], eax
 
pop edx ecx ebx eax
;DEBUGF 1,"extent.br_startoff : %d %d\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0]
;DEBUGF 1,"extent.br_startblock: %d %d\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0]
;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount]
;DEBUGF 1,"extent.br_state : %d\n",[ebp+XFS.extent.br_state]
ret 4
 
 
;----------------------------------------------------------------
; push namelen
; push name
; call xfs_hashname
;----------------------------------------------------------------
xfs_hashname: ; xfs_da_hashname
 
; simple hash function
; never fails)
 
push ecx esi
xor eax, eax
mov esi, [esp + 12] ; name
mov ecx, [esp + 16] ; namelen
;mov esi, '.'
;mov ecx, 1
;DEBUGF 1,"hashname: %d %s\n",ecx,esi
 
@@:
rol eax, 7
xor al, [esi]
add esi, 1
loop @b
 
pop esi ecx
ret 8
 
 
;----------------------------------------------------------------
; push len
; push base
; eax -- hash value
; call xfs_get_addr_by_hash
;----------------------------------------------------------------
xfs_get_addr_by_hash:
 
; look for the directory entry offset by its file name hash
; allows fast file search for block, leaf and node directories
; binary (ternary) search
 
;DEBUGF 1,"get_addr_by_hash\n"
push ebx esi
mov ebx, [esp + 12] ; left
mov edx, [esp + 16] ; len
.next:
mov ecx, edx
; jecxz .error
test ecx, ecx
jz .error
shr ecx, 1
mov esi, [ebx + ecx*8 + xfs_dir2_leaf_entry.hashval]
bswap esi
;DEBUGF 1,"cmp 0x%x",esi
cmp eax, esi
jb .below
ja .above
mov eax, [ebx + ecx*8 + xfs_dir2_leaf_entry.address]
pop esi ebx
ret 8
.below:
;DEBUGF 1,"b\n"
mov edx, ecx
jmp .next
.above:
;DEBUGF 1,"a\n"
lea ebx, [ebx + ecx*8 + 8]
sub edx, ecx
dec edx
jmp .next
.error:
mov eax, -1
pop esi ebx
ret 8
 
 
;----------------------------------------------------------------
; xfs_GetFileInfo - XFS implementation of getting file info
; in: ebp = pointer to XFS structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
xfs_GetFileInfo:
 
; lock partition
; get inode number by file name
; read inode
; get info
; unlock partition
 
push ecx edx esi edi
call xfs_lock
 
add esi, [esp + 20] ; name
;DEBUGF 1,"xfs_GetFileInfo: |%s|\n",esi
stdcall xfs_get_inode, esi
mov ecx, edx
or ecx, eax
jnz @f
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
 
stdcall xfs_get_inode_info, edx, [ebx + 16]
 
.quit:
call xfs_unlock
pop edi esi edx ecx
xor eax, eax
;DEBUGF 1,"quit\n\n"
ret
.error:
call xfs_unlock
pop edi esi edx ecx
;DEBUGF 1,"error\n\n"
ret
 
 
;----------------------------------------------------------------
; xfs_Read - XFS implementation of reading a file
; in: ebp = pointer to XFS structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
xfs_Read:
push ebx ecx edx esi edi
call xfs_lock
 
add esi, [esp + 24]
;DEBUGF 1,"xfs_Read: %d %d |%s|\n",[ebx+4],[ebx+12],esi
stdcall xfs_get_inode, esi
mov ecx, edx
or ecx, eax
jnz @f
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
mov [ebp + XFS.cur_inode_save], edx
 
cmp byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jne .not_extent_list
jmp .extent_list
.not_extent_list:
cmp byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jne .not_btree
jmp .btree
.not_btree:
DEBUGF 1,"XFS: NOT IMPLEMENTED: FILE FORMAT\n"
movi eax, ERROR_FS_FAIL
jmp .error
.extent_list:
mov ecx, [ebx + 12] ; bytes to read
mov edi, [ebx + 16] ; buffer for data
mov esi, [ebx + 8] ; offset_hi
mov ebx, [ebx + 4] ; offset_lo
 
mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
bswap eax
mov dword[ebp + XFS.bytes_left_in_file + 0], eax ; lo
mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
bswap eax
mov dword[ebp + XFS.bytes_left_in_file + 4], eax ; hi
 
mov eax, [edx + xfs_inode.di_core.di_nextents]
bswap eax
mov [ebp + XFS.left_extents], eax
 
mov dword[ebp + XFS.bytes_read], 0 ; actually read bytes
 
xor eax, eax ; extent offset in list
.extent_list.next_extent:
;DEBUGF 1,"extent_list.next_extent, eax: 0x%x\n",eax
;DEBUGF 1,"bytes_to_read: %d\n",ecx
;DEBUGF 1,"cur file offset: %d %d\n",esi,ebx
;DEBUGF 1,"esp: 0x%x\n",esp
cmp [ebp + XFS.left_extents], 0
jne @f
test ecx, ecx
jz .quit
movi eax, ERROR_END_OF_FILE
jmp .error
@@:
push eax
lea eax, [edx + xfs_inode.di_u + eax + xfs_bmbt_rec.l0]
stdcall xfs_extent_unpack, eax
pop eax
dec [ebp + XFS.left_extents]
add eax, sizeof.xfs_bmbt_rec
push eax ebx ecx edx esi
mov ecx, [ebp + XFS.blocklog]
shrd ebx, esi, cl
shr esi, cl
cmp esi, dword[ebp + XFS.extent.br_startoff + 4]
jb .extent_list.to_hole ; handle sparse files
ja @f
cmp ebx, dword[ebp + XFS.extent.br_startoff + 0]
jb .extent_list.to_hole ; handle sparse files
je .extent_list.to_extent ; read from the start of current extent
@@:
xor edx, edx
mov eax, [ebp + XFS.extent.br_blockcount]
add eax, dword[ebp + XFS.extent.br_startoff + 0]
adc edx, dword[ebp + XFS.extent.br_startoff + 4]
;DEBUGF 1,"br_startoff: %d %d\n",edx,eax
cmp esi, edx
ja .extent_list.skip_extent
jb .extent_list.to_extent
cmp ebx, eax
jae .extent_list.skip_extent
jmp .extent_list.to_extent
.extent_list.to_hole:
;DEBUGF 1,"extent_list.to_hole\n"
pop esi edx ecx ebx eax
jmp .extent_list.read_hole
.extent_list.to_extent:
;DEBUGF 1,"extent_list.to_extent\n"
pop esi edx ecx ebx eax
jmp .extent_list.read_extent
.extent_list.skip_extent:
;DEBUGF 1,"extent_list.skip_extent\n"
pop esi edx ecx ebx eax
jmp .extent_list.next_extent
 
.extent_list.read_hole:
;DEBUGF 1,"hole: offt: 0x%x%x ",esi,ebx
push eax edx
mov eax, dword[ebp + XFS.extent.br_startoff + 0]
mov edx, dword[ebp + XFS.extent.br_startoff + 4]
push esi ebx
mov ebx, ecx
sub eax, ebx ; get hole_size, it is 64 bit
sbb edx, 0 ; now edx:eax contains the size of hole
;DEBUGF 1,"size: 0x%x%x\n",edx,eax
jnz @f ; if hole size >= 2^32, write bytes_to_read zero bytes
cmp eax, ecx ; if hole size >= bytes_to_read, write bytes_to_read zeros
jae @f
mov ecx, eax ; if hole is < than bytes_to_read, write hole size zeros
@@:
sub ebx, ecx ; bytes_to_read - hole_size = left_to_read
add dword[esp + 0], ecx ; update pushed file offset
adc dword[esp + 4], 0
xor eax, eax ; hole is made of zeros
rep stosb
mov ecx, ebx
pop ebx esi
 
test ecx, ecx ; all requested bytes are read?
pop edx eax
jz .quit
jmp .extent_list.read_extent ; continue from the start of unpacked extent
 
.extent_list.read_extent:
;DEBUGF 1,"extent_list.read_extent\n"
push eax ebx ecx edx esi
mov eax, ebx
mov edx, esi
mov ecx, [ebp + XFS.blocklog]
shrd eax, edx, cl
shr edx, cl
sub eax, dword[ebp + XFS.extent.br_startoff + 0] ; skip esi:ebx ?
sbb edx, dword[ebp + XFS.extent.br_startoff + 4]
sub [ebp + XFS.extent.br_blockcount], eax
add dword[ebp + XFS.extent.br_startblock + 0], eax
adc dword[ebp + XFS.extent.br_startblock + 4], 0
.extent_list.read_extent.next_block:
;DEBUGF 1,"extent_list.read_extent.next_block\n"
cmp [ebp + XFS.extent.br_blockcount], 0 ; out of blocks in current extent?
jne @f
pop esi edx ecx ebx eax
jmp .extent_list.next_extent ; go to next extent
@@:
mov eax, dword[ebp + XFS.extent.br_startblock + 0]
mov edx, dword[ebp + XFS.extent.br_startblock + 4]
push ebx
mov ebx, [ebp + XFS.cur_block]
;DEBUGF 1,"read block: 0x%x%x\n",edx,eax
stdcall xfs_read_block
test eax, eax
pop ebx
jz @f
pop esi edx ecx ebx eax
movi eax, ERROR_FS_FAIL
jmp .error
@@:
dec [ebp + XFS.extent.br_blockcount]
add dword[ebp + XFS.extent.br_startblock + 0], 1
adc dword[ebp + XFS.extent.br_startblock + 4], 0
mov esi, [ebp + XFS.cur_block]
mov ecx, [ebp + XFS.blocklog]
mov eax, 1
shl eax, cl
dec eax ; get blocklog mask
and eax, ebx ; offset in current block
add esi, eax
neg eax
add eax, [ebp + XFS.blocksize]
mov ecx, [esp + 8] ; pushed ecx, bytes_to_read
cmp ecx, eax ; is current block enough?
jbe @f ; if so, read bytes_to_read bytes
mov ecx, eax ; otherwise read the block up to the end
@@:
sub [esp + 8], ecx ; left_to_read
add [esp + 12], ecx ; update current file offset, pushed ebx
sub dword[ebp + XFS.bytes_left_in_file + 0], ecx
sbb dword[ebp + XFS.bytes_left_in_file + 4], 0
jnc @f
add dword[ebp + XFS.bytes_left_in_file + 0], ecx
mov ecx, dword[ebp + XFS.bytes_left_in_file + 0]
mov dword[ebp + XFS.bytes_left_in_file + 0], 0
mov dword[ebp + XFS.bytes_left_in_file + 4], 0
@@:
add [ebp + XFS.bytes_read], ecx
adc [esp + 0], dword 0 ; pushed esi
;DEBUGF 1,"read data: %d\n",ecx
rep movsb
mov ecx, [esp + 8]
;DEBUGF 1,"left_to_read: %d\n",ecx
xor ebx, ebx
test ecx, ecx
jz @f
cmp dword[ebp + XFS.bytes_left_in_file + 4], 0
jne .extent_list.read_extent.next_block
cmp dword[ebp + XFS.bytes_left_in_file + 0], 0
jne .extent_list.read_extent.next_block
@@:
pop esi edx ecx ebx eax
jmp .quit
 
.btree:
mov ecx, [ebx + 12] ; bytes to read
mov [ebp + XFS.bytes_to_read], ecx
mov edi, [ebx + 16] ; buffer for data
mov esi, [ebx + 8] ; offset_hi
mov ebx, [ebx + 4] ; offset_lo
mov dword[ebp + XFS.file_offset + 0], ebx
mov dword[ebp + XFS.file_offset + 4], esi
mov [ebp + XFS.buffer_pos], edi
 
mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
bswap eax
mov dword[ebp + XFS.bytes_left_in_file + 0], eax ; lo
mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
bswap eax
mov dword[ebp + XFS.bytes_left_in_file + 4], eax ; hi
 
mov eax, [edx + xfs_inode.di_core.di_nextents]
bswap eax
mov [ebp + XFS.left_extents], eax
 
mov dword[ebp + XFS.bytes_read], 0 ; actually read bytes
 
push ebx ecx edx esi edi
mov [ebp + XFS.eof], 0
mov eax, dword[ebp + XFS.file_offset + 0]
mov edx, dword[ebp + XFS.file_offset + 4]
add eax, [ebp + XFS.bytes_to_read]
adc edx, 0
sub eax, dword[ebp + XFS.bytes_left_in_file + 0]
sbb edx, dword[ebp + XFS.bytes_left_in_file + 4]
jc @f ; file_offset + bytes_to_read < file_size
jz @f ; file_offset + bytes_to_read = file_size
mov [ebp + XFS.eof], 1
cmp edx, 0
jne .error.eof
sub dword[ebp + XFS.bytes_to_read], eax
jc .error.eof
jz .error.eof
@@:
stdcall xfs_btree_read, 0, 0, 1
pop edi esi edx ecx ebx
test eax, eax
jnz .error
cmp [ebp + XFS.eof], 1
jne .quit
jmp .error.eof
 
 
.quit:
call xfs_unlock
pop edi esi edx ecx ebx
xor eax, eax
mov ebx, [ebp + XFS.bytes_read]
;DEBUGF 1,"quit: %d\n\n",ebx
ret
.error.eof:
movi eax, ERROR_END_OF_FILE
.error:
;DEBUGF 1,"error\n\n"
call xfs_unlock
pop edi esi edx ecx ebx
mov ebx, [ebp + XFS.bytes_read]
ret
 
 
;----------------------------------------------------------------
; push max_offset_hi
; push max_offset_lo
; push nextents
; push block_number_hi
; push block_number_lo
; push extent_list
; -1 / read block number
;----------------------------------------------------------------
xfs_extent_list_read_dirblock: ; skips holes
;DEBUGF 1,"xfs_extent_list_read_dirblock\n"
push ebx esi edi
;mov eax, [esp+28]
;DEBUGF 1,"nextents: %d\n",eax
;mov eax, [esp+20]
;mov edx, [esp+24]
;DEBUGF 1,"block_number: 0x%x%x\n",edx,eax
;mov eax, [esp+32]
;mov edx, [esp+36]
;DEBUGF 1,"max_addr : 0x%x%x\n",edx,eax
mov ebx, [esp + 16]
mov esi, [esp + 20]
mov edi, [esp + 24]
; mov ecx, [esp + 28] ; nextents
.next_extent:
;DEBUGF 1,"next_extent\n"
dec dword[esp + 28]
js .error
stdcall xfs_extent_unpack, ebx
add ebx, sizeof.xfs_bmbt_rec ; next extent
mov edx, dword[ebp + XFS.extent.br_startoff + 4]
mov eax, dword[ebp + XFS.extent.br_startoff + 0]
cmp edx, [esp + 36] ; max_offset_hi
ja .error
jb @f
cmp eax, [esp + 32] ; max_offset_lo
jae .error
@@:
cmp edi, edx
jb .hole
ja .check_count
cmp esi, eax
jb .hole
ja .check_count
jmp .read_block
.hole:
;DEBUGF 1,"hole\n"
mov esi, eax
mov edi, edx
jmp .read_block
.check_count:
;DEBUGF 1,"check_count\n"
add eax, [ebp + XFS.extent.br_blockcount]
adc edx, 0
cmp edi, edx
ja .next_extent
jb .read_block
cmp esi, eax
jae .next_extent
; jmp .read_block
.read_block:
;DEBUGF 1,"read_block\n"
push esi edi
sub esi, dword[ebp + XFS.extent.br_startoff + 0]
sbb edi, dword[ebp + XFS.extent.br_startoff + 4]
add esi, dword[ebp + XFS.extent.br_startblock + 0]
adc edi, dword[ebp + XFS.extent.br_startblock + 4]
stdcall xfs_read_dirblock, esi, edi, [ebp + XFS.cur_dirblock]
pop edx eax
.quit:
;DEBUGF 1,"xfs_extent_list_read_dirblock: quit\n"
pop edi esi ebx
ret 24
.error:
;DEBUGF 1,"xfs_extent_list_read_dirblock: error\n"
xor eax, eax
dec eax
mov edx, eax
pop edi esi ebx
ret 24
 
 
;----------------------------------------------------------------
; push dirblock_num
; push nextents
; push extent_list
;----------------------------------------------------------------
xfs_dir2_node_get_numfiles:
 
; unfortunately, we need to set 'total entries' field
; this often requires additional effort, since there is no such a number in most directory ondisk formats
 
;DEBUGF 1,"xfs_dir2_node_get_numfiles\n"
push ebx ecx edx esi edi
 
mov eax, [esp + 24]
mov edx, [esp + 28]
mov esi, [esp + 32]
stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
mov ecx, eax
and ecx, edx
inc ecx
jnz @f
movi eax, ERROR_FS_FAIL
jmp .error
@@:
mov ebx, [ebp + XFS.cur_dirblock]
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
je .node
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
je .leaf
mov eax, ERROR_FS_FAIL
jmp .error
 
.node:
;DEBUGF 1,".node\n"
mov edi, [ebx + xfs_da_intnode.hdr.info.forw]
bswap edi
mov eax, [esp + 24]
mov edx, [esp + 28]
mov esi, [ebx + xfs_da_intnode.btree.before]
bswap esi
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
test eax, eax
jnz .error
jmp .common
.leaf:
;DEBUGF 1,".leaf\n"
movzx ecx, word[ebx + xfs_dir2_leaf.hdr.count]
xchg cl, ch
movzx eax, word[ebx + xfs_dir2_leaf.hdr.stale]
xchg al, ah
sub ecx, eax
add [ebp + XFS.entries_read], ecx
mov edi, [ebx + xfs_dir2_leaf.hdr.info.forw]
bswap edi
jmp .common
 
.common:
test edi, edi
jz .quit
mov esi, edi
mov eax, [esp + 24]
mov edx, [esp + 28]
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
test eax, eax
jnz .error
jmp .quit
 
.quit:
;DEBUGF 1,".quit\n"
pop edi esi edx ecx ebx
xor eax, eax
ret 12
.error:
;DEBUGF 1,".error\n"
pop edi esi edx ecx ebx
movi eax, ERROR_FS_FAIL
ret 12
 
 
;----------------------------------------------------------------
; push hash
; push dirblock_num
; push nextents
; push extent_list
;----------------------------------------------------------------
xfs_dir2_lookupdir_node:
DEBUGF 1,"xfs_dir2_lookupdir_node\n"
push ebx edx esi edi
 
mov eax, [esp + 20]
mov edx, [esp + 24]
mov esi, [esp + 28]
DEBUGF 1,"read dirblock: 0x%x %d\n",esi,esi
stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
DEBUGF 1,"dirblock read: 0x%x%x\n",edx,eax
mov ecx, eax
and ecx, edx
inc ecx
jnz @f
movi eax, ERROR_FS_FAIL
jmp .error
@@:
DEBUGF 1,"checkpoint #1\n"
mov ebx, [ebp + XFS.cur_dirblock]
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
je .node
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
je .leaf
mov eax, ERROR_FS_FAIL
DEBUGF 1,"checkpoint #2\n"
jmp .error
 
.node:
DEBUGF 1,".node\n"
mov edi, [esp + 32] ; hash
movzx ecx, word[ebx + xfs_da_intnode.hdr.count]
xchg cl, ch
mov [ebp + XFS.left_leaves], ecx
xor ecx, ecx
.node.next_leaf:
mov esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.hashval]
bswap esi
cmp edi, esi
jbe .node.leaf_found
inc ecx
cmp ecx, [ebp + XFS.left_leaves]
jne .node.next_leaf
mov eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
.node.leaf_found:
mov eax, [esp + 20]
mov edx, [esp + 24]
mov esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.before]
bswap esi
stdcall xfs_dir2_lookupdir_node, eax, edx, esi, edi
test eax, eax
jz .quit
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
 
.leaf:
DEBUGF 1,".leaf\n"
movzx ecx, [ebx + xfs_dir2_leaf.hdr.count]
xchg cl, ch
lea esi, [ebx + xfs_dir2_leaf.ents]
mov eax, [esp + 32]
stdcall xfs_get_addr_by_hash, esi, ecx
cmp eax, -1
je .error
mov ecx, eax
jmp .quit
 
.quit:
DEBUGF 1,".quit\n"
pop edi esi edx ebx
xor eax, eax
ret 16
.error:
DEBUGF 1,".error\n"
pop edi esi edx ebx
ret 16
 
 
;----------------------------------------------------------------
; push dirblock_num
; push nextents
; push extent_list
;----------------------------------------------------------------
xfs_dir2_btree_get_numfiles:
;DEBUGF 1,"xfs_dir2_node_get_numfiles\n"
push ebx ecx edx esi edi
 
mov eax, [esp + 24]
mov edx, [esp + 28]
mov esi, [esp + 32]
stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
mov ecx, eax
and ecx, edx
inc ecx
jnz @f
movi eax, ERROR_FS_FAIL
jmp .error
@@:
mov ebx, [ebp + XFS.cur_dirblock]
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
je .node
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
je .leaf
mov eax, ERROR_FS_FAIL
jmp .error
 
.node:
;DEBUGF 1,".node\n"
mov edi, [ebx + xfs_da_intnode.hdr.info.forw]
bswap edi
mov eax, [esp + 24]
mov edx, [esp + 28]
mov esi, [ebx + xfs_da_intnode.btree.before]
bswap esi
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
test eax, eax
jnz .error
jmp .common
.leaf:
;DEBUGF 1,".leaf\n"
movzx ecx, word[ebx + xfs_dir2_leaf.hdr.count]
xchg cl, ch
movzx eax, word[ebx + xfs_dir2_leaf.hdr.stale]
xchg al, ah
sub ecx, eax
add [ebp + XFS.entries_read], ecx
mov edi, [ebx + xfs_dir2_leaf.hdr.info.forw]
bswap edi
jmp .common
 
.common:
test edi, edi
jz .quit
mov esi, edi
mov eax, [esp + 24]
mov edx, [esp + 28]
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
test eax, eax
jnz .error
jmp .quit
 
.quit:
;DEBUGF 1,".quit\n"
pop edi esi edx ecx ebx
xor eax, eax
ret 12
.error:
;DEBUGF 1,".error\n"
pop edi esi edx ecx ebx
movi eax, ERROR_FS_FAIL
ret 12
 
 
;----------------------------------------------------------------
; push is_root
; push block_hi
; push block_lo
;----------------------------------------------------------------
xfs_btree_read:
push ebx ecx edx esi edi
cmp dword[esp + 32], 1 ; is root?
je .root
jmp .not_root
.root:
DEBUGF 1,".root\n"
mov ebx, [ebp + XFS.cur_inode_save]
add ebx, xfs_inode.di_u
movzx edx, [ebx + xfs_bmdr_block.bb_numrecs]
xchg dl, dh
dec edx
add ebx, sizeof.xfs_bmdr_block
xor eax, eax
dec eax
.root.next_key:
DEBUGF 1,".root.next_key\n"
cmp [ebp + XFS.bytes_to_read], 0
je .quit
inc eax
cmp eax, edx ; out of keys?
ja .root.key_found ; there is no length field, so try the last key
lea edi, [ebx + sizeof.xfs_bmbt_key*eax + 0]
lea esi, [ebx + sizeof.xfs_bmbt_key*eax + 4]
bswap edi
bswap esi
mov ecx, [ebp + XFS.blocklog]
shld edi, esi, cl
shl esi, cl
cmp edi, dword[ebp + XFS.file_offset + 4]
ja .root.prev_or_hole
jb .root.next_key
cmp esi, dword[ebp + XFS.file_offset + 0]
ja .root.prev_or_hole
jb .root.next_key
jmp .root.key_found
.root.prev_or_hole:
DEBUGF 1,".root.prev_or_hole\n"
test eax, eax
jz .root.hole
dec eax
jmp .root.key_found
.root.hole:
DEBUGF 1,".root.hole\n"
push eax edx esi edi
mov ecx, [ebp + XFS.blocklog]
shld edi, esi, cl
shl esi, cl
sub esi, dword[ebp + XFS.file_offset + 0]
sbb edi, dword[ebp + XFS.file_offset + 4]
mov ecx, [ebp + XFS.bytes_to_read]
cmp edi, 0 ; hole size >= 2^32
jne @f
cmp ecx, esi
jbe @f
mov ecx, esi
@@:
add dword[ebp + XFS.file_offset + 0], ecx
adc dword[ebp + XFS.file_offset + 4], 0
sub [ebp + XFS.bytes_to_read], ecx
xor eax, eax
mov edi, [ebp + XFS.buffer_pos]
rep stosb
mov [ebp + XFS.buffer_pos], edi
pop edi esi edx eax
jmp .root.next_key
.root.key_found:
DEBUGF 1,".root.key_found\n"
mov edx, [ebp + XFS.cur_inode_save]
mov eax, [ebp + XFS.inodesize]
sub eax, xfs_inode.di_u
cmp [edx + xfs_inode.di_core.di_forkoff], 0
je @f
movzx eax, [edx + xfs_inode.di_core.di_forkoff]
shl eax, XFS_DIR2_DATA_ALIGN_LOG ; 3
@@:
sub eax, sizeof.xfs_bmdr_block
shr eax, 4 ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr)
mov edx, [ebx + sizeof.xfs_bmbt_key*eax + 0] ; hi
mov eax, [ebx + sizeof.xfs_bmbt_key*eax + 4] ; hi
bswap edx
bswap eax
stdcall xfs_btree_read, eax, edx, 0
test eax, eax
jnz .error
jmp .root.next_key
 
.not_root:
DEBUGF 1,".root.not_root\n"
mov eax, [esp + 24] ; block_lo
mov edx, [esp + 28] ; block_hi
mov ebx, [ebp + XFS.cur_block]
stdcall xfs_read_block
test eax, eax
jnz .error
mov ebx, [ebp + XFS.cur_block]
 
cmp [ebx + xfs_bmbt_block.bb_magic], XFS_BMAP_MAGIC
jne .error
cmp [ebx + xfs_bmbt_block.bb_level], 0 ; leaf?
je .leaf
jmp .node
 
.node:
; mov eax, [ebp + XFS.blocksize]
; sub eax, sizeof.xfs_bmbt_block
; shr eax, 4 ; maxnumrecs
mov eax, dword[ebp + XFS.file_offset + 0] ; lo
mov edx, dword[ebp + XFS.file_offset + 4] ; hi
movzx edx, [ebx + xfs_bmbt_block.bb_numrecs]
xchg dl, dh
dec edx
add ebx, sizeof.xfs_bmbt_block
xor eax, eax
dec eax
.node.next_key:
push eax ecx edx esi edi
mov eax, [esp + 44] ; block_lo
mov edx, [esp + 48] ; block_hi
mov ebx, [ebp + XFS.cur_block]
stdcall xfs_read_block
test eax, eax
jnz .error
mov ebx, [ebp + XFS.cur_block]
add ebx, sizeof.xfs_bmbt_block
pop edi esi edx ecx eax
cmp [ebp + XFS.bytes_to_read], 0
je .quit
inc eax
cmp eax, edx ; out of keys?
ja .node.key_found ; there is no length field, so try the last key
lea edi, [ebx + sizeof.xfs_bmbt_key*eax + 0]
lea esi, [ebx + sizeof.xfs_bmbt_key*eax + 4]
bswap edi
bswap esi
mov ecx, [ebp + XFS.blocklog]
shld edi, esi, cl
shl esi, cl
cmp edi, dword[ebp + XFS.file_offset + 4]
ja .node.prev_or_hole
jb .node.next_key
cmp esi, dword[ebp + XFS.file_offset + 0]
ja .node.prev_or_hole
jb .node.next_key
jmp .node.key_found
.node.prev_or_hole:
test eax, eax
jz .node.hole
dec eax
jmp .node.key_found
.node.hole:
push eax edx esi edi
mov ecx, [ebp + XFS.blocklog]
shld edi, esi, cl
shl esi, cl
sub esi, dword[ebp + XFS.file_offset + 0]
sbb edi, dword[ebp + XFS.file_offset + 4]
mov ecx, [ebp + XFS.bytes_to_read]
cmp edi, 0 ; hole size >= 2^32
jne @f
cmp ecx, esi
jbe @f
mov ecx, esi
@@:
add dword[ebp + XFS.file_offset + 0], ecx
adc dword[ebp + XFS.file_offset + 4], 0
sub [ebp + XFS.bytes_to_read], ecx
xor eax, eax
mov edi, [ebp + XFS.buffer_pos]
rep stosb
mov [ebp + XFS.buffer_pos], edi
pop edi esi edx eax
jmp .node.next_key
.node.key_found:
mov edx, [ebp + XFS.cur_inode_save]
mov eax, [ebp + XFS.inodesize]
sub eax, xfs_inode.di_u
cmp [edx + xfs_inode.di_core.di_forkoff], 0
je @f
movzx eax, [edx + xfs_inode.di_core.di_forkoff]
shl eax, XFS_DIR2_DATA_ALIGN_LOG ; 3
@@:
sub eax, sizeof.xfs_bmdr_block
shr eax, 4 ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr)
mov edx, [ebx + sizeof.xfs_bmbt_key*eax + 0] ; hi
mov eax, [ebx + sizeof.xfs_bmbt_key*eax + 4] ; hi
bswap edx
bswap eax
stdcall xfs_btree_read, eax, edx, 0
test eax, eax
jnz .error
jmp .node.next_key
jmp .quit
 
.leaf:
jmp .quit
 
.error:
pop edi esi edx ecx ebx
movi eax, ERROR_FS_FAIL
ret 4
.quit:
pop edi esi edx ecx ebx
xor eax, eax
ret 4
 
 
;----------------------------------------------------------------
; push nextents
; push extent_list
; push file_offset_hi
; push file_offset_lo
;----------------------------------------------------------------
;xfs_extent_list_read:
; push ebx 0 edx esi edi ; zero means actually_read_bytes
;
; .quit:
; pop edi esi edx ecx ebx
; xor eax, eax
; ret 24
; .error:
; pop edi esi edx ecx ebx
; ret 24
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/trunk/fs/xfs.inc
0,0 → 1,518
; from stat.h
; distinguish file types
S_IFMT = 0170000o ; These bits determine file type.
S_IFDIR = 0040000o ; Directory.
S_IFCHR = 0020000o ; Character device.
S_IFBLK = 0060000o ; Block device.
S_IFREG = 0100000o ; Regular file.
S_IFIFO = 0010000o ; FIFO.
S_IFLNK = 0120000o ; Symbolic link.
S_IFSOCK = 0140000o ; Socket.
; end stat.h
 
 
; XFS null constant: empty fields must be all ones, not zeros!
XFS_NULL = -1
 
 
; static sector numbers
XFS_SECT_SB = 0
XFS_SECT_AGF = 1
XFS_SECT_AGI = 2
XFS_SECT_AGFL = 3
 
 
; signatures of file system structures
; 'string' numbers are treated by fasm as big endian
XFS_SB_MAGIC = 'XFSB'
XFS_AGF_MAGIC = 'XAGF'
XFS_AGI_MAGIC = 'XAGI'
XFS_ABTB_MAGIC = 'ABTB'
XFS_ABTC_MAGIC = 'ABTC'
XFS_IBT_MAGIC = 'IABT'
XFS_DINODE_MAGIC = 'IN'
XFS_BMAP_MAGIC = 'BMAP'
XFS_DA_NODE_MAGIC = 0xbefe ; those are little endian here
XFS_ATTR_LEAF_MAGIC = 0xeefb ; but big endian in docs
XFS_DIR2_LEAF1_MAGIC = 0xf1d2 ; pay attention!
XFS_DIR2_LEAFN_MAGIC = 0xffd2 ;
XFS_DIR2_BLOCK_MAGIC = 'XD2B'
XFS_DIR2_DATA_MAGIC = 'XD2D'
XFS_DIR2_FREE_MAGIC = 'XD2F'
XFS_DQUOT_MAGIC = 'DQ'
 
 
; bitfield lengths for packed extent
; MSB to LSB / left to right
BMBT_EXNTFLAG_BITLEN = 1
BMBT_STARTOFF_BITLEN = 54
BMBT_STARTBLOCK_BITLEN = 52
BMBT_BLOCKCOUNT_BITLEN = 21
 
 
; those constants are taken from linux source (xfs_dir2_leaf.h)
; they are magic infile offsets for directories
XFS_DIR2_DATA_ALIGN_LOG = 3 ; i.e., 8 bytes
XFS_DIR2_LEAF_SPACE = 1
XFS_DIR2_SPACE_SIZE = (1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG))
XFS_DIR2_LEAF_OFFSET = (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
XFS_DIR2_FREE_SPACE = 2
XFS_DIR2_SPACE_SIZE = (1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG))
XFS_DIR2_FREE_OFFSET = (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE)
 
 
; data section magic constants for directories (xfs_dir2_data.h)
XFS_DIR2_DATA_FD_COUNT = 3
XFS_DIR2_DATA_FREE_TAG = 0xffff
 
 
; valid inode formats
; enum xfs_dinode_fmt (xfs_dinode.h)
XFS_DINODE_FMT_DEV = 0 ; xfs_dev_t
XFS_DINODE_FMT_LOCAL = 1 ; one inode is enough (shortdir)
XFS_DINODE_FMT_EXTENTS = 2 ; one or more extents (leafdir, nodedir, regular files)
XFS_DINODE_FMT_BTREE = 3 ; highly fragmented files or really huge directories
XFS_DINODE_FMT_UUID = 4 ; uuid_t
 
 
; size of the unlinked inode hash table in the agi
XFS_AGI_UNLINKED_BUCKETS = 64
 
 
; possible extent states
; enum xfs_exntst_t (xfs_bmap_btree.h)
XFS_EXT_NORM = 0
XFS_EXT_UNWRITTEN = 1
XFS_EXT_DMAPI_OFFLINE = 2
XFS_EXT_INVALID = 3
 
 
; values for inode core flags / di_flags (xfs_dinode.h)
XFS_DIFLAG_REALTIME_BIT = 0 ; file's blocks come from rt area
XFS_DIFLAG_PREALLOC_BIT = 1 ; file space has been preallocated
XFS_DIFLAG_NEWRTBM_BIT = 2 ; for rtbitmap inode, new format
XFS_DIFLAG_IMMUTABLE_BIT = 3 ; inode is immutable
XFS_DIFLAG_APPEND_BIT = 4 ; inode is append-only
XFS_DIFLAG_SYNC_BIT = 5 ; inode is written synchronously
XFS_DIFLAG_NOATIME_BIT = 6 ; do not update atime
XFS_DIFLAG_NODUMP_BIT = 7 ; do not dump
XFS_DIFLAG_RTINHERIT_BIT = 8 ; create with realtime bit set
XFS_DIFLAG_PROJINHERIT_BIT = 9 ; create with parents projid
XFS_DIFLAG_NOSYMLINKS_BIT = 10 ; disallow symlink creation
XFS_DIFLAG_EXTSIZE_BIT = 11 ; inode extent size allocator hint
XFS_DIFLAG_EXTSZINHERIT_BIT = 12 ; inherit inode extent size
XFS_DIFLAG_NODEFRAG_BIT = 13 ; do not reorganize/defragment
XFS_DIFLAG_FILESTREAM_BIT = 14 ; use filestream allocator
XFS_DIFLAG_REALTIME = (1 SHL XFS_DIFLAG_REALTIME_BIT)
XFS_DIFLAG_PREALLOC = (1 SHL XFS_DIFLAG_PREALLOC_BIT)
XFS_DIFLAG_NEWRTBM = (1 SHL XFS_DIFLAG_NEWRTBM_BIT)
XFS_DIFLAG_IMMUTABLE = (1 SHL XFS_DIFLAG_IMMUTABLE_BIT)
XFS_DIFLAG_APPEND = (1 SHL XFS_DIFLAG_APPEND_BIT)
XFS_DIFLAG_SYNC = (1 SHL XFS_DIFLAG_SYNC_BIT)
XFS_DIFLAG_NOATIME = (1 SHL XFS_DIFLAG_NOATIME_BIT)
XFS_DIFLAG_NODUMP = (1 SHL XFS_DIFLAG_NODUMP_BIT)
XFS_DIFLAG_RTINHERIT = (1 SHL XFS_DIFLAG_RTINHERIT_BIT)
XFS_DIFLAG_PROJINHERIT = (1 SHL XFS_DIFLAG_PROJINHERIT_BIT)
XFS_DIFLAG_NOSYMLINKS = (1 SHL XFS_DIFLAG_NOSYMLINKS_BIT)
XFS_DIFLAG_EXTSIZE = (1 SHL XFS_DIFLAG_EXTSIZE_BIT)
XFS_DIFLAG_EXTSZINHERIT = (1 SHL XFS_DIFLAG_EXTSZINHERIT_BIT)
XFS_DIFLAG_NODEFRAG = (1 SHL XFS_DIFLAG_NODEFRAG_BIT)
XFS_DIFLAG_FILESTREAM = (1 SHL XFS_DIFLAG_FILESTREAM_BIT)
 
 
; superblock _ondisk_ structure (xfs_sb.h)
; this is _not_ the partition structure
; for XFS partition structure see XFS below
struct xfs_sb
sb_magicnum dd ? ; signature, must be XFS_SB_MAGIC
sb_blocksize dd ? ; block is the minimal file system unit, in bytes
sb_dblocks dq ? ; number of data blocks
sb_rblocks dq ? ; number of realtime blocks (not supported yet!)
sb_rextents dq ? ; number of realtime extents (not supported yet!)
sb_uuid rb 16 ; file system unique identifier
sb_logstart dq ? ; starting block of log (for internal journal; journals on separate devices are not supported!)
sb_rootino dq ? ; root inode number
sb_rbmino dq ? ; bitmap inode for realtime extents (ignored)
sb_rsumino dq ? ; summary inode for rt bitmap (ignored)
sb_rextsize dd ? ; realtime extent size, blocks
sb_agblocks dd ? ; size of an allocation group (the last one may be smaller!)
sb_agcount dd ? ; number of allocation groups
sb_rbmblocks dd ? ; number of rt bitmap blocks
sb_logblocks dd ? ; number of log blocks
sb_versionnum dw ? ; header version == XFS_SB_VERSION
sb_sectsize dw ? ; volume sector size in bytes (only 512B sectors are supported)
sb_inodesize dw ? ; inode size, bytes
sb_inopblock dw ? ; inodes per block
sb_fname rb 12 ; inodes per block (aka label)
sb_blocklog db ? ; log2 of sb_blocksize
sb_sectlog db ? ; log2 of sb_blocksize
sb_inodelog db ? ; log2 of sb_inodesize
sb_inopblog db ? ; log2 of sb_inopblock
sb_agblklog db ? ; log2 of sb_agblocks (rounded up!)
sb_rextslog db ? ; log2 of sb_rextents
sb_inprogress db ? ; mkfs is in progress, don't mount
sb_imax_pct db ? ; max % of fs for inode space
; statistics
sb_icount dq ? ; allocated inodes
sb_ifree dq ? ; free inodes
sb_fdblocks dq ? ; free data blocks
sb_frextents dq ? ; free realtime extents
 
sb_uquotino dq ? ; user quota inode
sb_gquotino dq ? ; group quota inode
sb_qflags dw ? ; quota flags
sb_flags db ? ; misc. flags
sb_shared_vn db ? ; shared version number
sb_inoalignmt dd ? ; inode chunk alignment, fsblocks
sb_unit dd ? ; stripe or raid unit
sb_width dd ? ; stripe or raid width
sb_dirblklog db ? ; log2 of dir block size (fsbs)
sb_logsectlog db ? ; log2 of the log sector size
sb_logsectsize dw ? ; sector size for the log, bytes
sb_logsunit dd ? ; stripe unit size for the log
sb_features2 dd ? ; additional feature bits
ends
 
 
; allocation group inode (xfs_ag.h)
struct xfs_agi
agi_magicnum dd ? ; magic number == XFS_AGI_MAGIC
agi_versionnum dd ? ; header version == XFS_AGI_VERSION
agi_seqno dd ? ; sequence number starting from 0
agi_length dd ? ; size in blocks of a.g.
agi_count dd ? ; count of allocated inodes
agi_root dd ? ; root of inode btree
agi_level dd ? ; levels in inode btree
agi_freecount dd ? ; number of free inodes
agi_newino dd ? ; new inode just allocated
agi_dirino dd ? ; last directory inode chunk
agi_unlinked rd XFS_AGI_UNLINKED_BUCKETS ; Hash table of inodes which have been unlinked but are still being referenced
ends
 
 
; superblock structure of b+tree node/leaf (same structure, bb_level matters)
struct xfs_btree_sblock
bb_magic dd ?
bb_level dw ? ; distinguishes nodeds and leaves
bb_numrecs dw ?
bb_leftsib dd ?
bb_rightsib dd ?
ends
 
 
; record of b+tree inode
struct xfs_inobt_rec
ir_startino dd ?
ir_freecount dd ?
ir_free dq ?
ends
 
 
; structure to store create, access and modification time in inode core
struct xfs_timestamp
t_sec dd ?
t_nsec dd ? ; nanoseconds
ends
 
 
; inode core structure: basic information about file
struct xfs_dinode_core
di_magic dw ? ; inode magic = XFS_DINODE_MAGIC
di_mode dw ? ; mode and type of file
di_version db ? ; inode version
di_format db ? ; format of di_c data
di_onlink dw ? ; old number of links to file
di_uid dd ? ; owner's user id
di_gid dd ? ; owner's group id
di_nlink dd ? ; number of links to file
di_projid dw ? ; owner's project id
di_pad rb 8 ; unused, zeroed space
di_flushiter dw ? ; incremented on flush
di_atime xfs_timestamp ; time last accessed
di_mtime xfs_timestamp ; time last modified
di_ctime xfs_timestamp ; time created/inode modified
di_size dq ? ; number of bytes in file
di_nblocks dq ? ; number of direct & btree blocks used
di_extsize dd ? ; basic/minimum extent size for file
di_nextents dd ? ; number of extents in data fork
di_anextents dw ? ; number of extents in attribute fork
di_forkoff db ? ; attr fork offs, <<3 for 64b align
di_aformat db ? ; format of attr fork's data
di_dmevmask dd ? ; DMIG event mask
di_dmstate dw ? ; DMIG state info
di_flags dw ? ; random flags, XFS_DIFLAG_...
di_gen dd ? ; generation number
ends
 
 
; shortform dir header
struct xfs_dir2_sf_hdr
count db ? ; the number of directory entries, used only if each inode number fits 4 bytes; zero otherwise
i8count db ? ; the number of directory entries, used only when count is zero
parent dq ? ; parent inode number: xfs_dir2_inou_t (4 or 8 bytes)
ends
 
 
; shortform dir entry
struct xfs_dir2_sf_entry
namelen db ? ; actual name length (ASCII)
offset rb 2 ; saved offset
name db ? ; name, variable size
; inumber dq ? ; xfs_dir2_inou_t
ends
 
 
; active entry in a data block
; aligned to 8 bytes
; tag appears as the last 2 bytes
struct xfs_dir2_data_entry
inumber dq ? ; inode number
namelen db ? ; name length
name db ? ; name bytes, no null
; tag dw ? ; starting offset of us
ends
 
 
; unused entry in a data block
; aligned to 8 bytes
; tag appears as the last 2 bytes
struct xfs_dir2_data_unused
freetag dw ? ; XFS_DIR2_DATA_FREE_TAG
length dw ? ; total free length
; tag dw ? ; starting offset of us
ends
 
 
; generic data entry
struct xfs_dir2_data_union
union
xentry xfs_dir2_data_entry
unused xfs_dir2_data_unused
ends
ends
 
 
; describe a free area in the data block
; the freespace will be formatted as a xfs_dir2_data_unused_t
struct xfs_dir2_data_free
offset dw ? ; start of freespace
length dw ? ; length of freespace
ends
 
 
; header for the data blocks
; always at the beginning of a directory-sized block
; the code knows that XFS_DIR2_DATA_FD_COUNT is 3
struct xfs_dir2_data_hdr
magic dd ? ; XFS_DIR2_DATA_MAGIC or XFS_DIR2_BLOCK_MAGIC
bestfree xfs_dir2_data_free
bestfree2 xfs_dir2_data_free
bestfree3 xfs_dir2_data_free
ends
 
 
; leaf block entry
struct xfs_dir2_leaf_entry
hashval dd ? ; hash value of name
address dd ? ; address of data entry
ends
 
 
; the tail of directory block
struct xfs_dir2_block_tail
count dd ? ; count of leaf entries
stale dd ? ; count of stale leaf entries
ends
 
 
; generic single-block structure, for xfs_db
struct xfs_dir2_block
hdr xfs_dir2_data_hdr
u xfs_dir2_data_union
; leaf xfs_dir2_leaf_entry
; tail xfs_dir2_block_tail
ends
 
 
;
struct xfs_dir2_data
hdr xfs_dir2_data_hdr ; magic XFS_DIR2_DATA_MAGIC
u xfs_dir2_data_union
ends
 
 
;
struct xfs_da_blkinfo
forw dd ? ; previous block in list
back dd ? ; following block in list
magic dw ? ; validity check on block
pad dw ? ; unused
ends
 
 
; leaf block header
struct xfs_dir2_leaf_hdr
info xfs_da_blkinfo ; header for da routines
count dw ? ; count of entries
stale dw ? ; count of stale entries
ends
 
 
; leaf block tail
struct xfs_dir2_leaf_tail
bestcount dd ?
ends
 
 
; leaf block
; bests and tail are at the end of the block for single-leaf only
; (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC)
struct xfs_dir2_leaf
hdr xfs_dir2_leaf_hdr ; leaf header
ents xfs_dir2_leaf_entry ; entries
; bests dw ? ; best free counts
; tail xfs_dir2_leaf_tail ; leaf tail
ends
 
 
; header of 'free' block part
struct xfs_dir2_free_hdr
magic dd ? ; XFS_DIR2_FREE_MAGIC
firstdb dd ? ; db of first entry
nvalid dd ? ; count of valid entries
nused dd ? ; count of used entries
ends
 
 
; 'free' part of directiry block
struct xfs_dir2_free
hdr xfs_dir2_free_hdr ; block header
bests dw ? ; best free counts
; unused entries are -1 (XFS_NULL)
ends
 
 
; b+tree node header
struct xfs_da_node_hdr
info xfs_da_blkinfo
count dw ?
level dw ?
ends
 
 
; b+tree node
struct xfs_da_node_entry
hashval dd ? ; hash value for this descendant
before dd ? ; Btree block before this key
ends
 
 
;
struct xfs_da_intnode
hdr xfs_da_node_hdr
btree xfs_da_node_entry
ends
 
 
; packet extent
struct xfs_bmbt_rec
l0 dq ?
l1 dq ?
ends
 
 
; unpacked extent
struct xfs_bmbt_irec
br_startoff dq ? ; starting file offset
br_startblock dq ? ; starting block number
br_blockcount dd ? ; number of blocks
br_state dd ? ; extent state
ends
 
 
; bmap root header, on-disk form only
struct xfs_bmdr_block
bb_level dw ? ; 0 is a leaf
bb_numrecs dw ? ; current number of data records
ends
 
 
; key structure for non-leaf levels of the tree
struct xfs_bmbt_key
br_startoff dq ? ; starting file offset
ends
 
 
sizeof.xfs_bmbt_ptr = 8 ; workaround
sizeof.xfs_bmdr_ptr = 8 ; workaround
 
 
; long form header: bmap btrees
; xfs_btree_lblock is xfs_bmbt_block (xfs_btree.h)
struct xfs_bmbt_block
bb_magic dd ? ; magic number for block type
bb_level dw ? ; 0 is a leaf
bb_numrecs dw ? ; current number of data records
bb_leftsib dq ? ; left sibling block or NULLDFSBNO
bb_rightsib dq ? ; right sibling block or NULLDFSBNO
ends
 
 
; high level inode structure
struct xfs_inode
di_core xfs_dinode_core ; main info, aka core
di_next_unlinked dd ? ; unlinked but still used inode (if any, XFS_NULL otherwise)
di_u db ? ; data fork inode part
; di_a db ? ; data attribute
ends
 
 
; internal data for every XFS partition
; this _is_ XFS partition structure
; most fields are unpacked or bswap'ed values from the superblock, so see xfs_sb structure above
struct XFS PARTITION
Lock MUTEX ? ; access mutex
blocksize dd ?
sectsize dd ?
dirblocksize dd ?
rootino dq ?
cur_block dd ?
cur_inode dd ?
cur_sect dd ?
cur_dirblock dd ?
tmp_inode dd ?
versionnum dd ?
features2 dd ?
inodesize dd ?
inopblock dd ?
blocklog dd ?
sectlog dd ?
inodelog dd ?
inopblog dd ?
agblklog dd ?
blockmsectlog dd ?
inodetoblocklog dd ?
dirblklog dd ?
sectpblock dd ?
agblocks dd ?
; helpers, temporary vars, etc
agblockmask dq ?
extent xfs_bmbt_irec
left_extents dd ?
left_leaves dd ?
bytes_to_read dd ?
bytes_read dd ?
entries_read dd ?
file_offset dq ?
max_dirblockaddr dd ?
next_block_num dq ?
dir2_leaf_offset_blocks dd ?
dir2_free_offset_blocks dd ?
cur_inode_save dd ?
bytes_left_in_file dq ?
ro_nextents dd ?
bb_ptrs dd ?
maxnumrecs dd ?
buffer_pos dd ?
eof dd ?
ends
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/trunk/kernel32.inc
192,6 → 192,7
include "fs/fs_lfn.inc" ; syscall, version 2
include "fs/iso9660.inc" ; read for iso9660 filesystem CD
include "fs/ext2.inc" ; read / write for ext2 filesystem
include "fs/xfs.asm" ; read / write for xfs filesystem
 
; sound