Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 7735 → Rev 7736

/kernel/trunk/fs/xfs.asm
1,199 → 1,311
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; Copyright (C) KolibriOS team 2013-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; XFS external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> XFS structure
; [esi]+[[esp+4]] = name
; out:
; eax, ebx = return values for sysfunc 70
 
include 'xfs.inc'
 
macro omit_frame_pointer_prologue procname,flag,parmbytes,localbytes,reglist {
local loc
loc = (localbytes+3) and (not 3)
if localbytes
sub esp, loc
end if
irps reg, reglist \{ push reg \}
counter = 0
irps reg, reglist \{counter = counter+1 \}
parmbase@proc equ esp+counter*4+loc+4
localbase@proc equ esp
}
 
macro omit_frame_pointer_epilogue procname,flag,parmbytes,localbytes,reglist {
local loc
loc = (localbytes+3) and (not 3)
irps reg, reglist \{ reverse pop reg \}
if localbytes
lea esp, [esp+loc]
end if
if flag and 10000b
retn
else
retn parmbytes
end if
}
 
prologue@proc equ omit_frame_pointer_prologue
epilogue@proc equ omit_frame_pointer_epilogue
 
macro movbe reg, arg {
if CPUID_MOVBE eq Y
movbe reg, arg
else
mov reg, arg
if reg in <eax,ebx,ecx,edx,esi,edi,ebp,esp>
bswap reg
else if ax eq reg
xchg al, ah
else if bx eq reg
xchg bl, bh
else if cx eq reg
xchg cl, ch
else if dx eq reg
xchg dl, dh
else
err
end if
end if
}
 
;
; This file contains XFS related code.
; For more information on XFS check links and source below.
;
; 1. https://xfs.wiki.kernel.org/
;
; 2. XFS Algorithms & Data Structures:
; git://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git
; https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
;
; 3. Linux source at https://www.kernel.org/
; git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
; /fs/xfs
;
 
iglobal
align 4
xfs_user_functions:
dd xfs_free
dd (xfs_user_functions_end - xfs_user_functions - 4) / 4
dd xfs_ReadFile
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_CreateFile
dd 0;xfs_WriteFile
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:
xfs._.user_functions_end:
endg
 
include 'xfs.inc'
 
; Mount if it's a valid XFS partition.
xfs_create_partition:
; in:
; ebp -> PARTITION structure
; ebx -> boot sector
; out:
; eax -> XFS structure, 0 = not XFS
push ebx ecx edx esi edi
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .error
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)
 
; test partition type (valid XFS one?)
; alloc and fill XFS (see xfs.inc) structure
; this function is called for each partition
; return 0 (not XFS or invalid) / pointer to partition structure
proc xfs_create_partition uses ebx esi edi
; check XFS signature
cmp [ebx+xfs_sb.sb_magicnum], XFS_SB_MAGIC
jnz .error_nofree
; test for supported feature flags and version in sb_versionnum
movzx eax, [ebx+xfs_sb.sb_versionnum]
xchg al, ah
; allow only known and supported features
; return error otherwise
test eax, NOT XFS_SB_VERSION_SUPPORTED
jnz .error_nofree
; version < 4 obsolete, not supported
; version = 4,5 supported
; version > 5 unknown
and al, XFS_SB_VERSION_NUMBITS
cmp al, 4
jb .error_nofree
cmp al, 5
ja .error_nofree
; if MOREBITS bit is set, additional feature flags are in sb_features2
test eax, XFS_SB_VERSION_MOREBITSBIT
jz @f
movbe eax, [ebx+xfs_sb.sb_features2]
test eax, NOT XFS_SB_VERSION2_SUPPORTED
jnz .error_nofree
@@:
movbe eax, [ebx+xfs_sb.sb_features_incompat]
test eax, NOT XFS_SB_FEAT_INCOMPAT_SUPPORTED
jnz .error_nofree
; all presented features are either supported or don't affect reading
movi eax, sizeof.XFS
call malloc
mov edi, eax
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, dword[ebp+PARTITION.FirstSector+DQ.lo]
mov dword[edi+XFS.FirstSector+DQ.lo], eax
mov eax, dword[ebp+PARTITION.FirstSector+DQ.hi]
mov dword[edi+XFS.FirstSector+DQ.hi], eax
mov eax, dword[ebp+PARTITION.Length+DQ.lo]
mov dword[edi+XFS.Length+DQ.lo], eax
mov eax, dword[ebp+PARTITION.Length+DQ.hi]
mov dword[edi+XFS.Length+DQ.hi], 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
 
mov [edi+XFS.FSUserFunctions], xfs._.user_functions
; here we initialize only one mutex (for the entire partition)
; XFS potentially allows parallel r/w access to different AGs, keep it in mind
lea ecx, [edi + XFS.Lock]
call mutex_init
 
; read superblock and fill just allocated XFS partition structure
; movzx eax, [ebx+xfs_sb.sb_sectsize]
; xchg al, ah
mov eax, [eax+DISK.MediaInfo.SectorSize]
mov [edi+XFS.sectsize], eax
 
mov eax, [ebx + xfs_sb.sb_blocksize]
bswap eax ; XFS is big endian
movbe eax, [ebx+xfs_sb.sb_blocksize]
mov [edi + XFS.blocksize], eax
movzx eax, word[ebx + xfs_sb.sb_sectsize]
 
movzx eax, [ebx+xfs_sb.sb_versionnum]
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
and eax, XFS_SB_VERSION_NUMBITS
mov [edi+XFS.version], eax
 
movbe eax, [ebx+xfs_sb.sb_features2]
mov [edi + XFS.features2], eax
movzx eax, word[ebx + xfs_sb.sb_inodesize]
cmp [edi+XFS.version], 5
jz .v5
.v4:
mov [edi+XFS.inode_core_size], sizeof.xfs_dinode_core
test eax, XFS_SB_VERSION2_FTYPE
setnz al
movzx eax, al
mov [edi+XFS.ftype_size], eax
mov [edi+XFS.dir_block_magic], XFS_DIR2_BLOCK_MAGIC
mov [edi+XFS.dir_data_magic], XFS_DIR2_DATA_MAGIC
mov [edi+XFS.dir_leaf1_magic], XFS_DIR2_LEAF1_MAGIC
mov [edi+XFS.dir_leafn_magic], XFS_DIR2_LEAFN_MAGIC
mov [edi+XFS.da_node_magic], XFS_DA_NODE_MAGIC
mov [edi+XFS.bmap_magic], XFS_BMAP_MAGIC
mov [edi+XFS.dir_block_size], sizeof.xfs_dir2_data_hdr
mov [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt_block
mov [edi+XFS.da_blkinfo_size], sizeof.xfs_da_blkinfo
jmp .vcommon
.v5:
mov [edi+XFS.inode_core_size], sizeof.xfs_dinode3_core
movbe eax, [ebx+xfs_sb.sb_features_incompat]
mov [edi+XFS.features_incompat], eax
test eax, XFS_SB_FEAT_INCOMPAT_FTYPE
setnz al
movzx eax, al
mov [edi+XFS.ftype_size], eax
mov [edi+XFS.dir_block_magic], XFS_DIR3_BLOCK_MAGIC
mov [edi+XFS.dir_data_magic], XFS_DIR3_DATA_MAGIC
mov [edi+XFS.dir_leaf1_magic], XFS_DIR3_LEAF1_MAGIC
mov [edi+XFS.dir_leafn_magic], XFS_DIR3_LEAFN_MAGIC
mov [edi+XFS.da_node_magic], XFS_DA3_NODE_MAGIC
mov [edi+XFS.bmap_magic], XFS_BMAP3_MAGIC
mov [edi+XFS.dir_block_size], sizeof.xfs_dir3_data_hdr
mov [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt3_block
mov [edi+XFS.da_blkinfo_size], sizeof.xfs_da3_blkinfo
.vcommon:
 
movzx eax, [ebx+xfs_sb.sb_inodesize]
xchg al, ah
mov [edi + XFS.inodesize], eax
movzx eax, word[ebx + xfs_sb.sb_inopblock] ; inodes per block
 
movzx eax, [ebx+xfs_sb.sb_inopblock]
xchg al, ah
mov [edi + XFS.inopblock], eax
movzx eax, byte[ebx + xfs_sb.sb_blocklog] ; log2 of block size, in bytes
 
movzx eax, [ebx+xfs_sb.sb_blocklog]
mov [edi + XFS.blocklog], eax
movzx eax, byte[ebx + xfs_sb.sb_sectlog]
 
; movzx eax, [ebx+xfs_sb.sb_sectlog]
mov eax, [edi+XFS.sectsize]
bsf eax, eax
mov [edi + XFS.sectlog], eax
movzx eax, byte[ebx + xfs_sb.sb_inodelog]
 
movzx eax, [ebx+xfs_sb.sb_inodelog]
mov [edi + XFS.inodelog], eax
movzx eax, byte[ebx + xfs_sb.sb_inopblog]
 
movzx eax, [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 ;
 
movzx ecx, [ebx+xfs_sb.sb_dirblklog]
mov [edi+XFS.dirblklog], ecx
movi eax, 1
shl eax, cl
mov [edi+XFS.blkpdirblk], eax
 
movbe eax, [ebx+xfs_sb.sb_rootino.hi]
mov [edi+XFS.rootino.lo], eax
movbe eax, [ebx+xfs_sb.sb_rootino.lo]
mov [edi+XFS.rootino.hi], 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
mov [edi+XFS.dirblocksize], eax ; blocks are for files, dirblocks are 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 [edi+XFS.sectpblog], ecx
 
mov eax, 1
shl eax, cl
mov [edi + XFS.sectpblock], eax
 
; shift order for inode_num->block_num conversion
movbe eax, [ebx+xfs_sb.sb_agblocks]
mov [edi+XFS.agblocks], eax
 
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]
movzx ecx, [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
xor edx, edx
shld edx, eax, cl
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
sub eax, 1
sbb edx, 0
mov [edi+XFS.agblockmask.lo], eax
mov [edi+XFS.agblockmask.hi], edx
 
; 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
shr edx, cl
mov [edi+XFS.dir2_leaf_offset_blocks.lo], eax
mov [edi+XFS.dir2_leaf_offset_blocks.hi], edx
 
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
shr edx, cl
mov [edi+XFS.dir2_free_offset_blocks.lo], eax
mov [edi+XFS.dir2_free_offset_blocks.hi], edx
 
; mov ecx, [edi + XFS.dirblklog]
; mov eax, [edi + XFS.blocksize]
; shl eax, cl
; mov [edi + XFS.dirblocksize], eax
 
; allocate memory for temp block, dirblock, inode, etc
mov eax, [edi + XFS.blocksize]
call malloc
mov [edi+XFS.cur_block], eax
test eax, eax
jz .error
mov [edi + XFS.cur_block], eax
 
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_block_data], eax
test eax, eax
jz .error
 
; we do need XFS.blocksize bytes for single inode
; minimal file system structure is block, inodes are packed in blocks
 
; FIXME
mov eax, [edi + XFS.blocksize]
call malloc
mov [edi+XFS.cur_inode], eax
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
201,212 → 313,185
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
 
; only for sector sized structures like AGF
; inodes usually fit this size, but not always!
; therefore never store inode here
mov eax, [edi + XFS.sectsize]
call malloc
mov [edi+XFS.cur_sect], eax
test eax, eax
jz .error
mov [edi + XFS.cur_sect], eax
 
; current directory block
 
mov eax, [edi + XFS.dirblocksize]
call malloc
mov [edi+XFS.cur_dirblock], eax
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
; return pointer to allocated XFS partition structure
mov eax, edi
ret
.error:
mov eax, edi
call xfs._.free
.error_nofree:
xor eax, eax
pop edi esi edx ecx ebx
ret
endp
 
 
; lock partition access mutex
proc xfs_lock
;DEBUGF 1,"xfs_lock\n"
xfs._.lock:
lea ecx, [ebp + XFS.Lock]
jmp mutex_lock
endp
 
 
; unlock partition access mutex
proc xfs_unlock
;DEBUGF 1,"xfs_unlock\n"
xfs._.unlock:
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
; or during failed initialization from xfs_create_partition
xfs._.free:
test eax, eax
jz .done
push ebx
mov ebx, eax
 
 
; freeing order must correspond the order of
; allocation in xfs_create_partition
mov eax, [ebx+XFS.cur_block]
test eax, eax
jz .done
call free
pop ebp
 
mov eax, [ebx+XFS.cur_block_data]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_inode]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.tmp_inode]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_sect]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_dirblock]
test eax, eax
jz .done
call free
 
 
mov eax, ebx
call free
pop ebx
.done:
ret
endp
 
 
;---------------------------------------------------------------
; block number (AG relative)
; block number
; eax -- inode_lo
; edx -- inode_hi
; ebx -- buffer
;---------------------------------------------------------------
xfs_read_block:
push ebx esi
proc xfs._.read_block
movi ecx, 1
call xfs._.read_blocks
ret
endp
 
push edx
push eax
 
proc xfs._.blkrel2sectabs uses esi
push edx 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
; to get absolute block number for fs_read64_sys we should
; 1. get AG number and multiply it by the AG size in blocks
; 2. extract and add AG relative block number
 
; 1.
mov ecx, [ebp + XFS.agblklog]
shrd eax, edx, cl
shr edx, cl
mul [ebp+XFS.agblocks]
; 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.
pop ecx esi
and ecx, [ebp+XFS.agblockmask.lo]
and esi, [ebp+XFS.agblockmask.hi]
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]
mov ecx, [ebp+XFS.sectpblog]
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
endp
 
 
;---------------------------------------------------------------
; push buffer
; push startblock_hi
; push startblock_lo
; call xfs_read_dirblock
; test eax, eax
; start block number
; edx:eax -- block
; ebx -- buffer
; ecx -- count
;---------------------------------------------------------------
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
proc xfs._.read_blocks
push ecx
call xfs._.blkrel2sectabs
pop ecx
imul ecx, [ebp+XFS.sectpblock]
call fs_read64_sys
test eax, eax
ret
endp
 
mov eax, [esp + 12] ; startblock_lo
mov edx, [esp + 16] ; startblock_hi
mov ebx, [esp + 20] ; buffer
 
; dirblock >= block
; read dirblocks by blocks
proc xfs._.read_dirblock uses ebx, _startblock:qword, _buffer
mov eax, dword[_startblock+DQ.lo]
mov edx, dword[_startblock+DQ.hi]
mov ebx, [_buffer]
mov ecx, [ebp+XFS.blkpdirblk]
call xfs._.read_blocks
ret
endp
 
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
 
proc xfs_read_inode uses ebx, _inode_lo, _inode_hi, _buffer
mov eax, [_inode_lo]
mov edx, [_inode_hi]
mov ebx, [_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]
mov ecx, [ebp+XFS.inopblog]
shrd eax, edx, cl
shr edx, cl
; 2.
call xfs_read_block
test eax, eax
call xfs._.read_block
jnz .error
; inode numbers should be first extracted from bitfields by mask
 
; note that inode numbers should be first extracted from bitfields using mask
 
mov eax, [esp + 8]
mov eax, [_inode_lo]
mov edx, 1
mov ecx, [ebp + XFS.inopblog]
shl edx, cl
415,2357 → 500,1625
mov ecx, [ebp + XFS.inodelog]
shl eax, cl
add ebx, eax
xor eax, eax
 
cmp word[ebx], XFS_DINODE_MAGIC ; test signature
jne .error
cmp [ebx+xfs_inode.di_core.di_magic], XFS_DINODE_MAGIC
jz .quit
movi eax, ERROR_FS_FAIL
.quit:
xor eax, eax
mov edx, ebx
pop ebx
ret 12
.error:
movi eax, ERROR_FS_FAIL
mov edx, ebx
pop ebx
ret 12
ret
endp
 
 
;----------------------------------------------------------------
; 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]
; skip ecx first entries
proc xfs._.dir_sf_skip _count
mov ecx, [_count]
.next:
dec ecx
js .shortdir.fill
js .quit
dec [ebp+XFS.entries_left_in_dir]
js .quit
.self:
bts [ebp+XFS.dir_sf_self_done], 0
jc .parent
jmp .next
.parent:
bts [ebp+XFS.dir_sf_parent_done], 0
jc .common
jmp .next
.common:
movzx eax, [esi+xfs_dir2_sf_entry.namelen]
add esi, xfs_dir2_sf_entry.name
add esi, eax
add esi, [ebp+XFS.ftype_size]
add esi, [ebp+XFS.shortform_inodelen]
jmp .next
.quit:
ret
endp
 
; 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], '..'
proc xfs._.dir_sf_read uses edi, _count
locals
_dst dd ?
endl
.next:
dec [_count]
js .quit
dec [ebp+XFS.entries_left_in_dir]
js .quit
mov [_dst], edx
.self:
bts [ebp+XFS.dir_sf_self_done], 0
jc .parent
lea edi, [edx+bdfe.name]
mov dword[edi], '.'
stdcall xfs_get_inode_info, [ebp+XFS.cur_inode], edx
jmp .common
.parent:
bts [ebp+XFS.dir_sf_parent_done], 0
jc .not_special
lea edi, [edx+bdfe.name] ; get file name offset
mov dword[edi], '..' ; terminator included
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]
lea edx, [ebx+xfs_dir2_sf.hdr.parent]
call xfs._.get_inode_number_sf
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]
stdcall xfs_get_inode_info, edx, edi
jmp .common
.not_special:
movzx ecx, [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
lea edi, [edx+bdfe.name]
stdcall xfs._.copy_filename
add esi, [ebp+XFS.ftype_size]
mov edi, edx
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [esi + 4], [esi]
mov edx, esi
call xfs._.get_inode_number_sf
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
stdcall xfs_get_inode_info, edx, edi
add esi, [ebp+XFS.shortform_inodelen]
.common:
mov edx, [_dst]
mov eax, [ebp+XFS.bdfe_nameenc]
mov [edx+bdfe.nameenc], eax
add edx, [ebp+XFS.bdfe_len]
inc [ebp+XFS.entries_read]
jmp .next
.quit:
xor eax, eax
.error:
ret
endp
 
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
proc xfs._.readdir_sf uses esi, _src, _dst
mov ebx, [_src]
mov edx, [_dst]
mov [ebp+XFS.dir_sf_self_done], 0
mov [ebp+XFS.dir_sf_parent_done], 0
mov [ebp+XFS.entries_read], 0
movzx eax, [ebx+xfs_dir2_sf.hdr.count]
; '..' and '.' are implicit
add eax, 2
mov [ebp+XFS.entries_left_in_dir], eax
mov [edx+bdfe_hdr.total_cnt], eax
; inode numbers are often saved as 4 bytes (iff they fit)
; compute the length of inode numbers
; 8 iff i8count != 0, 4 otherwise
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
setnz al
lea eax, [eax*4+4]
mov [ebp+XFS.shortform_inodelen], eax
add edx, sizeof.bdfe_hdr
lea esi, [ebx+xfs_dir2_sf.hdr.parent+eax]
stdcall xfs._.dir_sf_skip, [ebp+XFS.entries_to_skip]
stdcall xfs._.dir_sf_read, [ebp+XFS.requested_cnt]
ret
endp
 
 
proc xfs._.readdir_block _literal_area, _out_buf
mov ebx, [_literal_area]
mov [ebp+XFS.entries_read], 0
mov eax, ebx
mov ebx, [ebp+XFS.cur_dirblock]
stdcall xfs._.extent_unpack, eax
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
mov edx, [_out_buf]
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.dir_block_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
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
movbe ecx, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.stale]
movbe eax, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
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 [ebp+XFS.entries_left_in_dir], eax
mov [edx+bdfe_hdr.total_cnt], eax
 
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
add ebx, [ebp+XFS.dir_block_size]
add edx, sizeof.bdfe_hdr
mov [_out_buf], edx
lea edi, [_out_buf]
.next:
movi eax, ERROR_SUCCESS
cmp [ebp+XFS.requested_cnt], 0
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
@@:
cmp [ebp+XFS.entries_left_in_dir], 0
jz .quit
stdcall xfs._.dir_entry_skip_read, edi
jz .next
.error:
.quit:
ret
endp
 
 
proc xfs._.readdir_leaf_node uses esi, _inode_data, _out_buf
mov ebx, [_inode_data]
mov edx, [_out_buf]
mov [ebp+XFS.cur_inode_save], ebx
mov [ebp+XFS.entries_read], 0
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0
jnz .error
mov eax, [ebp+XFS.entries_read]
mov edx, [_out_buf]
mov [edx+bdfe_hdr.total_cnt], eax
mov [ebp+XFS.entries_left_in_dir], eax
add [_out_buf], sizeof.bdfe_hdr
mov [ebp+XFS.entries_read], 0
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
lea ecx, [_out_buf]
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
mov [ebp+XFS.offset_begin.lo], 0
mov [ebp+XFS.offset_begin.hi], 0
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
pop ecx
dec ecx
jnz .blockdir.next_entry
jmp .quit
stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx
; jnz .error
.error:
.quit:
ret
endp
 
.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
proc xfs._.dir_entry_skip_read uses esi edi, _arg
cmp [ebx+xfs_dir2_data_union.unused.freetag], XFS_NULL
jnz @f
movzx eax, [ebx+xfs_dir2_data_union.unused.length]
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
cmp [ebp+XFS.entries_to_skip], 0
jz .read
.skip:
dec [ebp+XFS.entries_to_skip]
movzx ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
lea ebx, [ebx+xfs_dir2_data_union.xentry.name+ecx+2]
add ebx, [ebp+XFS.ftype_size]
jmp .common
.read:
dec [ebp+XFS.requested_cnt]
inc [ebp+XFS.entries_read]
mov edi, [_arg]
mov edi, [edi]
movbe edx, [ebx+xfs_dir2_data_union.xentry.inumber.lo]
movbe eax, [ebx+xfs_dir2_data_union.xentry.inumber.hi]
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]
mov edx, [_arg]
mov edx, [edx]
mov ecx, [ebp+XFS.bdfe_nameenc]
mov [edx+bdfe.nameenc], ecx
lea edi, [edx+bdfe.name]
movzx ecx, [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
stdcall xfs._.copy_filename
lea ebx, [esi + 2] ; skip 'tag'
add ebx, [ebp+XFS.ftype_size]
mov eax, [_arg]
mov edx, [eax]
add edx, [ebp+XFS.bdfe_len]
mov [eax], edx
.common:
sub ebx, [ebp+XFS.cur_dirblock]
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
add ebx, [ebp+XFS.cur_dirblock]
dec [ebp+XFS.entries_left_in_dir]
.quit:
movi eax, ERROR_SUCCESS
cmp esp, esp
.error:
ret
endp
 
.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
 
proc xfs._.dir_btree_skip_read uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
mov ebx, [_cur_dirblock]
mov eax, [ebp+XFS.dir_data_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
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]
mov eax, ebx
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
; add ebx, xfs_dir2_block.u
add ebx, [ebp+XFS.dir_block_size]
.next:
movi eax, ERROR_SUCCESS
cmp [ebp+XFS.requested_cnt], 0
jz .quit
cmp [ebp+XFS.entries_left_in_dir], 0
jz .quit
cmp ebx, [ebp+XFS.max_dirblockaddr]
jz .quit
stdcall xfs._.dir_entry_skip_read, [_arg]
jz .next
.error:
.quit:
ret
endp
 
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"
proc xfs._.readdir_btree uses esi, _inode_data, _out_buf
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 [ebp+XFS.entries_read], 0
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
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
lea edx, [ebx+xfs_inode.di_u]
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0, 1
mov eax, [ebp + XFS.entries_read]
mov edx, [_out_buf]
mov [edx+bdfe_hdr.total_cnt], eax
mov [ebp+XFS.entries_left_in_dir], eax
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]
add [_out_buf], sizeof.bdfe_hdr
mov eax, [ebp+XFS.inodesize]
sub eax, xfs_inode.di_u
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
mov [esp + 28], eax
mov [edx + 4], eax ; number of actually read entries
lea edx, [ebx+xfs_inode.di_u]
mov [ebp+XFS.offset_begin.lo], 0
mov [ebp+XFS.offset_begin.hi], 0
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
mov ecx, [_out_buf]
push ecx
mov ecx, esp
stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx, 1
pop ecx
.error:
.quit:
ret
endp
 
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
proc xfs._.copy_filename uses eax
mov eax, [ebp+XFS.bdfe_nameenc]
cmp eax, 3
jz .utf8
cmp eax, 2
jz .utf16
.cp866:
call unicode.utf8.decode
call unicode.cp866.encode
stosb
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
jnz .cp866
mov byte[edi], 0
jmp .done
.utf16:
call unicode.utf8.decode
call unicode.utf16.encode
stosw
shr eax, 16
jz @f
stosw
@@:
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
test ecx, ecx
jnz .utf16
mov word[edi], 0
jmp .done
.utf8:
rep movsb
mov byte[edi], 0
.done:
ret
endp
 
;----------------------------------------------------------------
; src ; inode
; dst ; bdfe
; start_number ; from 0
;----------------------------------------------------------------
proc xfs._.readdir uses ebx esi edi, _start_number, _entries_to_read, _dst, _src, _encoding
mov ecx, [_start_number]
mov [ebp+XFS.entries_to_skip], ecx
mov eax, [_entries_to_read]
mov [ebp+XFS.requested_cnt], eax
mov eax, [_encoding]
mov [ebp+XFS.bdfe_nameenc], eax
mov ecx, 304
cmp eax, 1 ; CP866
jbe @f
mov ecx, 560
@@:
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
mov [ebp+XFS.bdfe_len], ecx
mov edx, [_dst]
mov [ebp+XFS.bdfe_buf], edx
mov ebx, [_src]
mov [ebp+XFS.cur_inode_save], ebx
 
mov [edx+bdfe_hdr.version], 1
mov [edx+bdfe_hdr.zeroed+0x00], 0
mov [edx+bdfe_hdr.zeroed+0x04], 0
mov [edx+bdfe_hdr.zeroed+0x08], 0
mov [edx+bdfe_hdr.zeroed+0x0c], 0
mov [edx+bdfe_hdr.zeroed+0x10], 0
 
movzx eax, [ebx+xfs_inode.di_core.di_format]
; switch directory ondisk format and jump to corresponding label
cmp eax, XFS_DINODE_FMT_LOCAL
jnz @f
pop edx ecx
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.readdir_sf, ebx, [_dst]
test eax, eax
jnz .error
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
cmp eax, XFS_DINODE_FMT_BTREE
jnz @f
stdcall xfs._.readdir_btree, ebx, [_dst]
jmp .quit
@@:
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
cmp eax, XFS_DINODE_FMT_EXTENTS
movi eax, ERROR_FS_FAIL
jnz .error
call xfs._.get_last_dirblock
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
jnz @f
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.readdir_block, ebx, [_dst]
jmp .quit
 
 
@@:
stdcall xfs._.readdir_leaf_node, ebx, [_dst]
jmp .quit
.quit:
pop edi esi edx ecx
add esp, 4 ; pop vars
mov edx, [_dst]
mov ebx, [ebp+XFS.entries_read]
mov [edx+bdfe_hdr.read_cnt], ebx
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
ret
endp
 
 
;----------------------------------------------------------------
; 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"
; returns edx:eax inode or 0
proc xfs._.lookup_sf _name, _len
add ebx, [ebp+XFS.inode_core_size]
mov esi, [_name]
mov ecx, [_len]
cmp ecx, 2
ja .common
jz .check_parent
.check_self:
cmp byte[esi], '.'
jnz .common
mov eax, [ebp+XFS.inode_self.lo]
mov edx, [ebp+XFS.inode_self.hi]
jmp .quit
.check_parent:
cmp word[esi], '..'
jnz .common
lea edx, [ebx+xfs_dir2_sf.hdr.parent]
call xfs._.get_inode_number_sf
jmp .quit
.common:
movzx edx, [ebx+xfs_dir2_sf.hdr.count]
movi eax, 0
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
setnz al
lea eax, [eax*4+4]
lea edi, [ebx+xfs_dir2_sf.hdr.parent+eax]
.next_name:
dec edx
jns @f
movi eax, ERROR_FILE_NOT_FOUND
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]
movzx ecx, [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
mov esi, [_name]
cmp ecx, [_len]
jnz @f
repz cmpsb
jz .found
@@:
add edi, [ebp+XFS.ftype_size]
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
jmp .next_name
.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
add edi, [ebp+XFS.ftype_size]
mov edx, edi
call xfs._.get_inode_number_sf
.quit:
cmp esp, esp
.error:
ret
endp
 
.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
 
proc xfs._.lookup_block uses esi, _name, _len
add ebx, [ebp+XFS.inode_core_size]
mov eax, ebx
mov ebx, [ebp+XFS.cur_dirblock]
stdcall xfs._.extent_unpack, eax
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
jnz .error
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
mov eax, [ebp+XFS.dir_block_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_hashname, [_name+4], [_len]
add ebx, [ebp+XFS.dirblocksize]
movbe ecx, [ebx-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
lea edx, [ecx*sizeof.xfs_dir2_leaf_entry+sizeof.xfs_dir2_block_tail]
sub ebx, edx
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
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
movbe edx, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.lo]
movbe eax, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.hi]
.quit:
.error:
ret
endp
 
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
 
proc xfs._.get_inode_by_addr uses ebx esi edi, _inode_buf
xor edx, edx
shld edx, eax, XFS_DIR2_DATA_ALIGN_LOG
shl eax, XFS_DIR2_DATA_ALIGN_LOG
mov esi, [ebp+XFS.dirblocksize]
dec esi
and esi, eax
mov ecx, [ebp+XFS.blocklog]
add ecx, [ebp+XFS.dirblklog]
shrd eax, edx, cl
shr edx, cl
mov ecx, [ebp+XFS.dirblklog]
shld edx, eax, cl
shl eax, cl
mov ebx, [_inode_buf]
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jz .extents
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jz .btree
jmp .error
.extents:
movbe ecx, [ebx+xfs_inode.di_core.di_nextents]
add ebx, [ebp+XFS.inode_core_size]
mov [ebp+XFS.offset_begin.lo], eax
mov [ebp+XFS.offset_begin.hi], edx
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
jmp .common
.btree:
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
shl ecx, 3
test ecx, ecx
jnz @f
mov ecx, [ebp+XFS.inodesize]
sub ecx, [ebp+XFS.inode_core_size]
@@:
shl eax, 3
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
.common:
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
mov eax, [ebp+XFS.dir_data_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
movbe edx, [ebx+esi+xfs_dir2_data_entry.inumber.lo]
movbe eax, [ebx+esi+xfs_dir2_data_entry.inumber.hi]
.error:
.quit:
ret
endp
 
.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
 
proc xfs._.lookup_leaf uses ebx esi edi, _name, _len
movbe ecx, [ebx+xfs_inode.di_core.di_nextents]
add ebx, [ebp+XFS.inode_core_size]
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .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
movzx eax, [ebp+XFS.dir_leaf1_magic]
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], ax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_hashname, [_name+4], [_len]
cmp [ebp+XFS.version], 5
jz .v5
.v4:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
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
jmp .vcommon
.v5:
movzx ecx, [ebx+xfs_dir3_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir3_leaf.ents
.vcommon:
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
.error:
ret
endp
 
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
@@:
 
proc xfs._.lookup_node uses ebx esi edi, _name, _len
locals
.hash dd ?
endl
mov [ebp+XFS.cur_inode_save], ebx
stdcall xfs_hashname, [_name+4], [_len]
mov [.hash], eax
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov esi, [ebp+XFS.dir2_leaf_offset_blocks.lo]
.begin:
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 eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ebx, eax
mov [ebp+XFS.offset_begin.lo], esi
mov [ebp+XFS.offset_begin.hi], 0
stdcall xfs._.extent_list.seek, edx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .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
movzx eax, [ebp+XFS.da_node_magic]
cmp [ebx+xfs_da_intnode.hdr.info.magic], ax
jz .node
movzx eax, [ebp+XFS.dir_leafn_magic]
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], ax
jz .leaf
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
jmp .error
.node:
cmp [ebp+XFS.version], 5
jz .node.v5
.node.v4:
lea eax, [ebx+sizeof.xfs_da_intnode]
movzx edx, [ebx+xfs_da_intnode.hdr.count]
jmp .node.vcommon
.node.v5:
lea eax, [ebx+sizeof.xfs_da3_intnode]
movzx edx, [ebx+xfs_da3_intnode.hdr.count]
.node.vcommon:
xchg dl, dh
stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
jnz .error
bswap ecx
;DEBUGF 1,"got address: 0x%x\n",ecx
mov esi, eax
jmp .begin
.leaf:
cmp [ebp+XFS.version], 5
jz .leaf.v5
.leaf.v4:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
jmp .leaf.vcommon
.leaf.v5:
movzx ecx, [ebx+xfs_dir3_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir3_leaf.ents
.leaf.vcommon:
mov eax, [.hash]
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
cmp esp, esp
ret
.error:
test esp, esp
ret
endp
 
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"
proc xfs._.lookup_btree uses ebx esi edi, _name, _len
locals
.hash dd ?
endl
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
stdcall xfs_hashname, [_name+4], [_len]
mov [.hash], eax
mov edx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
jmp .next_level.first
.next_level:
lea eax, [ebx+sizeof.xfs_da_intnode]
movzx edx, [ebx+xfs_da_intnode.hdr.count]
xchg dl, dh
stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
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
xor edx, edx
.next_level.first:
mov ebx, [ebp+XFS.cur_inode_save]
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
shl ecx, 3
test ecx, ecx
jnz @f
mov ecx, [ebp+XFS.inodesize]
sub ecx, xfs_inode.di_u
@@:
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
add ebx, xfs_inode.di_u
stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
mov ebx, [ebp+XFS.cur_dirblock]
cmp [ebx+xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
jz .next_level
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
jz .leafn
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], XFS_DIR2_LEAF1_MAGIC
jnz .error
bswap ecx
DEBUGF 1,"got address: 0x%x\n",ecx
 
mov eax, [.hash]
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
jmp .got_addr
.leafn:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
mov eax, [.hash]
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
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
 
.got_addr:
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
ret 12
cmp esp, esp
ret
.error:
xor eax, eax
mov edx, eax
ret 12
test esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; push name
; call xfs_get_inode
; test eax, eax
;----------------------------------------------------------------
xfs_get_inode:
; call xfs_get_inode_short until file is found / error returned
; search for the _name in _inode dir
; called for each /path/component/to/my/file
; out:
; ZF/zf = ok/fail
; edx:eax = inode/garbage:error
proc xfs._.get_inode_short uses esi, _inode:qword, _len, _name
mov esi, [_name]
mov eax, dword[_inode+DQ.lo]
mov edx, dword[_inode+DQ.hi]
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
; switch directory ondisk format
mov ebx, edx
mov [ebp+XFS.cur_inode_save], ebx
movzx eax, [ebx+xfs_inode.di_core.di_format]
cmp eax, XFS_DINODE_FMT_LOCAL
mov edi, xfs._.lookup_sf
jz .lookup
cmp eax, XFS_DINODE_FMT_BTREE
mov edi, xfs._.lookup_btree
jz .lookup
cmp eax, XFS_DINODE_FMT_EXTENTS
jnz .error
call xfs._.get_last_dirblock
test eax, eax
mov edi, xfs._.lookup_block
jz .lookup
cmp edx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov edi, xfs._.lookup_node
ja .lookup
cmp eax, [ebp+XFS.dir2_free_offset_blocks.lo]
jae .lookup
mov edi, xfs._.lookup_leaf
.lookup:
stdcall edi, [_name+4], [_len]
.error:
ret
endp
 
;DEBUGF 1,"getting inode of: %s\n",[esp+4]
push ebx esi edi
 
; ZF/zf = ok/fail
; edx:eax = inode/garbage:error
proc xfs_get_inode uses ebx esi edi, _name
; call *._.get_inode_short until file is found / error returned
; 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
 
mov eax, [ebp+XFS.rootino.lo]
mov edx, [ebp+XFS.rootino.hi]
mov esi, [_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
@@:
cmp byte[esi], '/'
jnz @f
test eax, eax
jz .error
inc esi
jmp @b
@@:
jmp .next_dir ; file name found, go to next directory level
 
cmp byte[esi], 0
jz .found
push esi
inc esi
@@:
cmp byte[esi], 0
jz @f
cmp byte[esi], '/'
jz @f
inc esi
jmp @b
@@:
mov ecx, esi
sub ecx, [esp]
mov [ebp+XFS.inode_self.lo], eax
mov [ebp+XFS.inode_self.hi], edx
stdcall xfs._.get_inode_short, eax, edx, ecx ; esi pushed above
jz .next_dir
.error:
.found:
ret
endp
 
.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: esi
; 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
; out: [edx] -- f70.1 out structure
proc xfs_ReadFolder uses esi edi
call xfs._.lock
stdcall xfs_get_inode, esi
pop edi esi ebx
mov ecx, edx
or ecx, eax
jnz @f
movi eax, ERROR_FILE_NOT_FOUND
@@:
 
; 3.
jnz .error
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
stdcall xfs._.readdir, [ebx+f70s1arg.start_idx], [ebx+f70s1arg.count], [ebx+f70s1arg.buf], edx, [ebx+f70s1arg.encoding]
test eax, eax
jnz .error
mov edx, [ebx+f70s1arg.buf]
mov ecx, [ebx+f70s1arg.count]
cmp [edx+bdfe_hdr.read_cnt], ecx
jz .quit
movi eax, ERROR_END_OF_FILE
.quit:
mov ebx, [edx+bdfe_hdr.read_cnt]
 
.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
call xfs._.unlock
pop eax
ret
endp
 
 
;----------------------------------------------------------------
; 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
; edx -- pointer to inode number in big endian
; ZF -- must be set at exit
proc xfs._.get_inode_number_sf
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
jz .i4bytes
.i8bytes:
mov edx, [esp + 12] ; hi
mov eax, [esp + 8] ; lo
bswap edx ; big endian
bswap eax
ret 12
movbe eax, [edx+DQ.hi]
movbe edx, [edx+DQ.lo]
ret
.i4bytes:
xor edx, edx ; no hi
mov eax, [esp + 12] ; hi = lo
bswap eax ; big endian
ret 12
movbe eax, [edx+DQ.lo]
xor edx, edx
ret
endp
 
 
;----------------------------------------------------------------
; push dest
; push src
; call xfs_get_inode_info
;----------------------------------------------------------------
xfs_get_inode_info:
 
proc xfs_get_inode_info uses ebx, _src, _dst
; 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]
mov edx, [_src]
movzx ecx, [edx+xfs_inode.di_core.di_mode]
xchg cl, ch
;DEBUGF 1,"di_mode: %x\n",ecx
test ecx, S_IFDIR ; directory?
test ecx, S_IFDIR
jz @f
mov eax, 0x10 ; set directory flag
movi eax, 0x10 ; set directory flag
@@:
mov edi, [_dst]
mov [edi+bdfe.attr], eax
movbe eax, [edx+xfs_inode.di_core.di_size.lo]
mov [edi+bdfe.size.hi], eax
movbe eax, [edx+xfs_inode.di_core.di_size.hi]
mov [edi+bdfe.size.lo], eax
 
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
movbe eax, [edx+xfs_inode.di_core.di_ctime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
mov eax, [edx + xfs_inode.di_core.di_atime.t_sec]
bswap eax
movbe eax, [edx+xfs_inode.di_core.di_atime.t_sec]
push edx
sub eax, 978307200
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
mov eax, [edx + xfs_inode.di_core.di_mtime.t_sec]
bswap eax
movbe eax, [edx+xfs_inode.di_core.di_mtime.t_sec]
push edx
sub eax, 978307200
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
.quit:
xor eax, eax
ret 8
.error:
movi eax, ERROR_FS_FAIL
ret 8
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; push extent_data
; call xfs_extent_unpack
;----------------------------------------------------------------
xfs_extent_unpack:
 
proc xfs._.extent_unpack uses eax ebx ecx edx, _extent_data
; extents come as packet 128bit bitfields
; lets unpack them to access internal fields
; unpack them to access internal fields
; write result to the XFS.extent structure
mov ebx, [_extent_data]
 
push eax ebx ecx edx
mov ebx, [esp + 20]
 
xor eax, eax
mov edx, [ebx + 0]
bswap edx
movbe edx, [ebx+0]
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
movbe eax, [ebx+4]
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 [ebp+XFS.extent.br_startoff.lo], eax
mov [ebp+XFS.extent.br_startoff.hi], edx
 
mov edx, [ebx + 4]
mov eax, [ebx + 8]
mov ecx, [ebx + 12]
bswap edx
bswap eax
bswap ecx
movbe edx, [ebx+4]
movbe eax, [ebx+8]
movbe ecx, [ebx+12]
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 [ebp+XFS.extent.br_startblock.lo], ecx
mov [ebp+XFS.extent.br_startblock.hi], eax
 
mov eax, [ebx + 12]
bswap eax
movbe eax, [ebx+12]
and eax, 0x001fffff ; mask
mov [ebp + XFS.extent.br_blockcount], eax
ret
endp
 
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
proc xfs_hashname uses ecx esi, _name, _len
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
 
mov esi, [_name]
mov ecx, [_len]
@@:
rol eax, 7
xor al, [esi]
add esi, 1
loop @b
dec ecx
jnz @b
ret
endp
 
pop esi ecx
ret 8
 
 
;----------------------------------------------------------------
; push len
; push base
; eax -- hash value
; call xfs_get_addr_by_hash
;----------------------------------------------------------------
xfs_get_addr_by_hash:
 
proc xfs._.get_addr_by_hash uses ebx esi, _base, _len
; 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
mov ebx, [_base]
mov edx, [_len]
.next:
mov ecx, edx
; jecxz .error
test ecx, ecx
jz .error
jz .not_found
shr ecx, 1
mov esi, [ebx + ecx*8 + xfs_dir2_leaf_entry.hashval]
bswap esi
;DEBUGF 1,"cmp 0x%x",esi
movbe esi, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.hashval]
cmp eax, esi
jb .below
ja .above
mov eax, [ebx + ecx*8 + xfs_dir2_leaf_entry.address]
pop esi ebx
ret 8
movbe eax, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.address]
ret
.below:
;DEBUGF 1,"b\n"
mov edx, ecx
jmp .next
.above:
;DEBUGF 1,"a\n"
lea ebx, [ebx + ecx*8 + 8]
lea ebx, [ebx+(ecx+1)*sizeof.xfs_dir2_leaf_entry]
sub edx, ecx
dec edx
jmp .next
.error:
mov eax, -1
pop esi ebx
ret 8
.not_found:
movi eax, ERROR_FILE_NOT_FOUND
test esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; xfs_GetFileInfo - XFS implementation of getting file info
; xfs_GetFileInfo: XFS implementation of getting file info
; in: ebp = pointer to XFS structure
; in: esi+[esp+4] = name
; in: esi = 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
proc xfs_GetFileInfo uses ecx edx esi edi
call xfs._.lock
stdcall xfs_get_inode, esi
mov ecx, edx
or ecx, eax
jnz @f
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
jnz .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]
 
stdcall xfs_get_inode_info, edx, [ebx+f70s5arg.buf]
.quit:
call xfs_unlock
pop edi esi edx ecx
call xfs._.unlock
xor eax, eax
;DEBUGF 1,"quit\n\n"
ret
.error:
call xfs_unlock
pop edi esi edx ecx
;DEBUGF 1,"error\n\n"
push eax
call xfs._.unlock
pop eax
ret
endp
 
 
proc xfs._.file.read_extent uses ebx ecx edx, _callback, _callback_data
mov eax, [ebp+XFS.file_offset.lo]
mov edx, [ebp+XFS.file_offset.hi]
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
mov ecx, [ebp+XFS.blocklog]
shld edi, esi, cl
shl esi, cl
cmp edx, edi
jb .hole
ja .try_head
cmp eax, esi
ja .try_head
jz .try_match
.hole:
sub esi, eax
sbb edi, edx
movi ecx, -1
test edi, edi
jnz @f
mov ecx, esi
@@:
cmp ecx, [ebp+XFS.bytes_to_read]
jbe @f
mov ecx, [ebp+XFS.bytes_to_read]
@@:
mov edi, [ebp+XFS.file_buffer]
xor eax, eax
sub [ebp+XFS.bytes_to_read], ecx
sub [ebp+XFS.bytes_left_in_file.lo], ecx
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], ecx
add [ebp+XFS.file_buffer], ecx
add [ebp+XFS.file_offset.lo], ecx
adc [ebp+XFS.file_offset.hi], 0
rep stosb
cmp [ebp+XFS.bytes_to_read], 0
jz .quit
jmp .try_match
.try_head:
mov eax, [ebp+XFS.file_offset.lo]
mov ecx, [ebp+XFS.blocksize]
dec ecx
test eax, ecx
jz .try_match
.head:
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.cur_block_data]
stdcall xfs._.read_block
mov esi, [ebp+XFS.cur_block_data]
mov edi, [ebp+XFS.file_buffer]
mov eax, [ebp+XFS.file_offset.lo]
mov ecx, [ebp+XFS.blocksize]
dec ecx
and eax, ecx
add esi, eax
inc ecx
sub ecx, eax
cmp ecx, [ebp+XFS.bytes_to_read]
jbe @f
mov ecx, [ebp+XFS.bytes_to_read]
@@:
sub [ebp+XFS.bytes_to_read], ecx
sub [ebp+XFS.bytes_left_in_file.lo], ecx
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], ecx
add [ebp+XFS.file_buffer], ecx
add [ebp+XFS.file_offset.lo], ecx
adc [ebp+XFS.file_offset.hi], 0
rep movsb
add [ebp+XFS.extent.br_startoff.lo], 1
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], 1
adc [ebp+XFS.extent.br_startblock.hi], 0
dec [ebp+XFS.extent.br_blockcount]
; cmp [ebp+XFS.bytes_to_read], 0
jz .quit
.try_match:
mov eax, [ebp+XFS.bytes_to_read]
test eax, eax
jz .quit
cmp eax, [ebp+XFS.blocksize]
jb .tail
mov ecx, [ebp+XFS.blocklog]
shr eax, cl
cmp eax, [ebp+XFS.extent.br_blockcount]
jbe @f
mov eax, [ebp+XFS.extent.br_blockcount]
@@:
mov ecx, eax
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.file_buffer]
push ecx
stdcall xfs._.read_blocks
pop eax
add [ebp+XFS.extent.br_startoff.lo], eax
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], eax
adc [ebp+XFS.extent.br_startblock.hi], 0
sub [ebp+XFS.extent.br_blockcount], eax
imul eax, [ebp+XFS.blocksize]
sub [ebp+XFS.bytes_to_read], eax
sub [ebp+XFS.bytes_left_in_file.lo], eax
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], eax
add [ebp+XFS.file_buffer], eax
add [ebp+XFS.file_offset.lo], eax
adc [ebp+XFS.file_offset.hi], 0
; cmp [ebp+XFS.bytes_to_read], 0
cmp [ebp+XFS.extent.br_blockcount], 0
jz .quit
.tail:
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.cur_block_data]
stdcall xfs._.read_block
mov ecx, [ebp+XFS.bytes_to_read]
cmp [ebp+XFS.bytes_left_in_file.hi], 0
jnz @f
cmp ecx, [ebp+XFS.bytes_left_in_file.lo]
jbe @f
mov ecx, [ebp+XFS.bytes_left_in_file.lo]
@@:
mov esi, [ebp+XFS.cur_block_data]
mov edi, [ebp+XFS.file_buffer]
mov eax, ecx
rep movsb
add [ebp+XFS.bytes_read], eax
sub [ebp+XFS.bytes_to_read], eax
sub [ebp+XFS.bytes_left_in_file.lo], eax
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.file_buffer], eax
add [ebp+XFS.file_offset.lo], eax
adc [ebp+XFS.file_offset.hi], 0
add [ebp+XFS.extent.br_startoff.lo], 1
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], 1
adc [ebp+XFS.extent.br_startblock.hi], 0
dec [ebp+XFS.extent.br_blockcount]
.quit:
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; xfs_ReadFile - XFS implementation of reading a file
; in: ebp = pointer to XFS structure
; in: esi+[esp+4] = name
; in: esi = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
xfs_ReadFile:
push ebx ecx edx esi edi
call xfs_lock
add esi, [esp + 24]
proc xfs_Read uses ecx edx esi edi
locals
.offset_begin DQ ?
.offset_end DQ ?
endl
call xfs._.lock
mov [ebp+XFS.bytes_read], 0
mov eax, [ebx+f70s0arg.count]
mov [ebp+XFS.bytes_to_read], eax
test eax, eax
jz .quit
mov eax, [ebx+f70s0arg.buf]
mov [ebp+XFS.file_buffer], eax
mov eax, [ebx+f70s0arg.offset.hi]
mov [ebp+XFS.file_offset.hi], eax
mov eax, [ebx+f70s0arg.offset.lo]
mov [ebp+XFS.file_offset.lo], eax
 
stdcall xfs_get_inode, esi
mov ecx, edx
or ecx, eax
jnz @f
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
jnz .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
mov ebx, edx
; precompute .offset_begin
mov esi, [ebp+XFS.file_offset.lo]
mov edi, [ebp+XFS.file_offset.hi]
mov ecx, [ebp+XFS.blocklog]
shrd esi, edi, cl
shr edi, cl
mov [.offset_begin.lo], esi
mov [.offset_begin.hi], edi
; precompute .offset_end
mov esi, [ebp+XFS.file_offset.lo]
mov edi, [ebp+XFS.file_offset.hi]
add esi, [ebp+XFS.bytes_to_read]
adc edi, 0
mov ecx, [ebp+XFS.blocksize]
dec ecx
add esi, ecx
adc edi, 0
mov ecx, [ebp+XFS.blocklog]
shrd esi, edi, cl
shr edi, cl
mov [.offset_end.lo], esi
mov [.offset_end.hi], edi
 
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
movbe ecx, [ebx+xfs_inode.di_core.di_size.hi]
movbe edx, [ebx+xfs_inode.di_core.di_size.lo]
mov [ebp+XFS.bytes_left_in_file.lo], ecx
mov [ebp+XFS.bytes_left_in_file.hi], edx
 
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
sub ecx, [ebp+XFS.file_offset.lo]
sbb edx, [ebp+XFS.file_offset.hi]
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
jb .error
mov [ebp+XFS.eof], 0
test edx, edx
jnz @f
cmp ecx, [ebp+XFS.bytes_to_read]
jae @f
mov ecx, eax ; if hole is < than bytes_to_read, write hole size zeros
mov [ebp+XFS.eof], ERROR_END_OF_FILE
mov [ebp+XFS.bytes_to_read], ecx
@@:
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
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jz .btree
.extent_list:
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
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ecx, [.offset_begin.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [.offset_begin.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [.offset_end.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [.offset_end.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.file.read_extent, 0, 0
jnz .error
jmp .hole_check
.btree:
mov eax, [ebp+XFS.inodesize]
sub eax, [ebp+XFS.inode_core_size]
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
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
mov edx, ebx
add edx, [ebp+XFS.inode_core_size]
mov ecx, [.offset_begin.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [.offset_begin.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [.offset_end.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [.offset_end.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_btree, edx, eax, xfs._.file.read_extent, 0, 0, 1
.hole_check:
cmp [ebp+XFS.bytes_left_in_file.hi], 0
jnz @f
cmp [ebp+XFS.bytes_left_in_file.lo], 0
jz .hole_done
@@:
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
@@:
cmp [ebp+XFS.bytes_to_read], 0
jz .hole_done
mov ebx, [ebp+XFS.cur_inode_save]
movbe edx, [ebx+xfs_inode.di_core.di_size.lo]
movbe eax, [ebx+xfs_inode.di_core.di_size.hi]
sub eax, [ebp+XFS.file_offset.lo]
sbb edx, [ebp+XFS.file_offset.hi]
jc .hole_done
mov ecx, [ebp+XFS.bytes_to_read]
test edx, edx
jnz .hole_read
cmp eax, [ebp+XFS.bytes_to_read]
jae .hole_read
mov ecx, eax
jmp .hole_read
.hole_read:
sub [ebp+XFS.bytes_to_read], ecx
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
 
 
mov edi, [ebp+XFS.file_buffer]
xor eax, eax
rep stosb
.hole_done:
.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
mov eax, [ebp+XFS.eof]
.error:
;DEBUGF 1,"error\n\n"
call xfs_unlock
pop edi esi edx ecx ebx
push eax
call xfs._.unlock
pop eax
mov ebx, [ebp + XFS.bytes_read]
ret
endp
 
 
;----------------------------------------------------------------
; 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
proc xfs._.leafn_calc_entries uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
mov edx, [_cur_dirblock]
movzx eax, [ebp+XFS.da_node_magic]
cmp [edx+xfs_dir2_leaf.hdr.info.magic], ax
jz .quit
cmp [ebp+XFS.version], 5
jnz @f
add edx, xfs_dir3_leaf.hdr.count-xfs_dir2_leaf.hdr.count
@@:
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
movzx eax, [edx+xfs_dir2_leaf.hdr.count]
movzx ecx, [edx+xfs_dir2_leaf.hdr.stale]
xchg al, ah
xchg cl, ch
sub eax, ecx
add [ebp+XFS.entries_read], 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
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; 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
proc xfs._.get_before_by_hashval uses ebx edx esi edi, _base, _count, _hash
mov edi, [_hash]
mov edx, [_count]
xor ecx, ecx
.node.next:
movbe eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
cmp [ebp+XFS.version], 5
jnz @f
movbe eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
@@:
cmp eax, edi
ja .node.leaf_found
inc ecx
cmp ecx, edx
jnz .node.next
movi eax, ERROR_FILE_NOT_FOUND
test esp, esp
jmp .error
.node.leaf_found:
movbe eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
cmp [ebp+XFS.version], 5
jnz @f
movi eax, ERROR_FS_FAIL
jmp .error
movbe eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
@@:
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
jmp .quit
.error:
test esp, esp
ret
.quit:
cmp esp, esp
ret
endp
 
.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]
proc xfs._.long_btree.seek uses ebx esi edi, _ptr, _size
mov ebx, [_ptr]
mov esi, [_size]
sub esi, sizeof.xfs_bmdr_block
shr esi, 4
shl esi, 3
movzx eax, [ebx+xfs_bmdr_block.bb_level]
movzx ecx, [ebx+xfs_bmdr_block.bb_numrecs]
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
add ebx, sizeof.xfs_bmdr_block
jmp .common
 
.not_root:
mov esi, [ebp+XFS.blocksize]
sub esi, sizeof.xfs_bmbt_block
shr esi, 4
shl esi, 3
movzx eax, [ebx+xfs_bmbt_block.bb_level]
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, sizeof.xfs_bmbt_block
.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
jz .leaf
.node:
.next_rec:
dec ecx
js .error
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.lo]
cmp [ebp+XFS.offset_begin.hi], eax
ja .node_found
jb .next_rec
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.hi]
cmp [ebp+XFS.offset_begin.lo], eax
jae .node_found
jmp .next_rec
.node_found:
add ebx, esi
movbe edx, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.lo]
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.hi]
mov ebx, [ebp+XFS.cur_block]
stdcall xfs._.read_block
test eax, eax
jnz .error
mov ebx, [ebp+XFS.cur_block]
jmp .not_root
.leaf:
jmp .quit
 
.error:
.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
ret
endp
 
 
;----------------------------------------------------------------
; 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
proc xfs._.walk_btree uses ebx esi edi, _ptr, _size, _callback_extent, _callback_block, _callback_data, _is_root
stdcall xfs._.long_btree.seek, [_ptr+4], [_size]
mov [_is_root], 0
.begin:
mov ebx, [ebp+XFS.cur_block]
mov eax, [ebp+XFS.bmap_magic]
cmp [ebx+xfs_bmbt_block.bb_magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, [ebp+XFS.bmbt_block_size]
stdcall xfs._.walk_extent_list, ecx, ebx, [_callback_extent+8], [_callback_block+4], [_callback_data]
jnz .error
mov esi, [ebp+XFS.offset_begin.lo]
mov edi, [ebp+XFS.offset_begin.hi]
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
sub ebx, [ebp+XFS.bmbt_block_size]
movbe edx, [ebx+xfs_bmbt_block.bb_rightsib.lo]
movbe eax, [ebx+xfs_bmbt_block.bb_rightsib.hi]
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
mov ebx, [ebp+XFS.cur_block]
stdcall xfs._.read_block
jnz .error
jmp .begin
.error:
.quit:
ret
endp
 
.leaf:
DEBUGF 1,".leaf\n"
movzx ecx, [ebx + xfs_dir2_leaf.hdr.count]
 
proc xfs._.btree_read_block uses ebx esi edi, _tree, _size, _block_lo, _block_hi, _buf
mov eax, [_block_lo]
mov [ebp+XFS.offset_begin.lo], eax
mov eax, [_block_hi]
mov [ebp+XFS.offset_begin.hi], eax
stdcall xfs._.long_btree.seek, [_tree+4], [_size]
jnz .error
mov ebx, [ebp+XFS.cur_block]
mov eax, [ebp+XFS.bmap_magic]
cmp [ebx+xfs_bmbt_block.bb_magic], eax
jnz .error
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
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
 
add ebx, [ebp+XFS.bmbt_block_size]
mov eax, [_block_lo]
mov [ebp+XFS.offset_begin.lo], eax
mov eax, [_block_hi]
mov [ebp+XFS.offset_begin.hi], eax
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [_buf]
.error:
.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
ret
endp
 
 
;----------------------------------------------------------------
; 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
proc xfs._.extent_list.seek uses esi, _count
sub ebx, sizeof.xfs_bmbt_rec
inc [_count]
.find_low:
add ebx, sizeof.xfs_bmbt_rec
dec [_count]
jz .quit
stdcall xfs._.extent_unpack, ebx
mov eax, [ebp+XFS.extent.br_startoff.lo]
mov edx, [ebp+XFS.extent.br_startoff.hi]
mov esi, [ebp+XFS.extent.br_blockcount]
add eax, esi
adc edx, 0
 
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
cmp edx, [ebp+XFS.offset_begin.hi]
ja .low_found
jb .find_low
cmp eax, [ebp+XFS.offset_begin.lo]
ja .low_found
jmp .find_low
.low_found:
add ebx, sizeof.xfs_bmbt_rec
 
.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
mov eax, [ebp+XFS.offset_begin.lo]
mov edx, [ebp+XFS.offset_begin.hi]
mov esi, eax
sub esi, [ebp+XFS.extent.br_startoff.lo]
jbe .quit
; same br_blockcount for block and dirblock?
mov [ebp+XFS.extent.br_startoff.lo], eax
mov [ebp+XFS.extent.br_startoff.hi], edx
sub [ebp+XFS.extent.br_blockcount], esi
add [ebp+XFS.extent.br_startblock.lo], esi
adc [ebp+XFS.extent.br_startblock.hi], 0
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
mov eax, [_count]
ret
endp
 
 
;----------------------------------------------------------------
; 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"
proc xfs._.extent_iterate_dirblocks _callback, _callback_data
.check_high:
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
jb .read_dirblock
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
.read_dirblock:
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
mov edx, [ebp+XFS.cur_dirblock]
mov eax, [_callback]
stdcall eax, edx, esi, edi, [_callback_data]
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
mov eax, [ebp+XFS.blkpdirblk]
add esi, eax
adc edi, 0
add [ebp+XFS.extent.br_startblock.lo], eax
adc [ebp+XFS.extent.br_startblock.hi], 0
sub [ebp+XFS.extent.br_blockcount], eax
jnz .check_high
.error:
.quit:
ret
endp
 
.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
proc xfs._.walk_extent_list uses ebx esi edi, _count, _ptr, _callback_extent, _callback_block, _callback_data
mov ebx, [_ptr]
stdcall xfs._.extent_list.seek, [_count]
mov [_count], eax
dec [_count]
js .quit
jmp .next_extent.decoded
.next_extent:
stdcall xfs._.extent_unpack, ebx
add ebx, sizeof.xfs_bmbt_rec
.next_extent.decoded:
mov eax, [ebp+XFS.extent.br_blockcount]
add [ebp+XFS.offset_begin.lo], eax
adc [ebp+XFS.offset_begin.hi], 0
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
stdcall [_callback_extent+8], [_callback_block+4], [_callback_data]
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
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
jb @f
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
@@:
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
dec [_count]
js .quit
jmp .next_extent
.quit:
movi eax, ERROR_SUCCESS
.error:
test eax, eax
jnz .error
jmp .node.next_key
jmp .quit
ret
endp
 
.leaf:
 
jmp .quit
proc xfs._.get_last_dirblock uses ecx
movbe eax, [ebx+xfs_inode.di_core.di_nextents]
assert (sizeof.xfs_bmbt_rec AND (sizeof.xfs_bmbt_rec - 1)) = 0
shl eax, BSF sizeof.xfs_bmbt_rec
add eax, [ebp+XFS.inode_core_size]
lea eax, [ebx+eax-sizeof.xfs_bmbt_rec]
stdcall xfs._.extent_unpack, eax
xor edx, edx
mov eax, [ebp+XFS.extent.br_blockcount]
mov ecx, [ebp+XFS.dirblklog]
shr eax, cl
dec eax
add eax, [ebp+XFS.extent.br_startoff.lo]
adc edx, [ebp+XFS.extent.br_startoff.hi]
ret
endp
 
.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
restore prologue@proc,epilogue@proc
restore movbe