0,0 → 1,2769 |
include 'xfs.inc' |
|
; |
; This file contains XFS related code. |
; For more information on XFS check sources below. |
; |
; 1. XFS Filesystem Structure, 2nd Edition, Revision 1. Silicon Graphics Inc. 2006 |
; 2. Linux source http://kernel.org |
; |
|
|
; test partition type (valid XFS one?) |
; alloc and fill XFS (see xfs.inc) structure |
; this function is called for each partition |
; returns 0 (not XFS or invalid) / pointer to partition structure |
xfs_create_partition: |
push ebx ecx edx esi edi |
cmp dword[ebx + xfs_sb.sb_magicnum], XFS_SB_MAGIC ; signature |
jne .error |
|
; TODO: check XFS.versionnum and XFS.features2 |
; print superblock params for debugging (waiting for bug reports) |
|
movi eax, sizeof.XFS |
call malloc |
test eax, eax |
jz .error |
|
; standard partition initialization, common for all file systems |
|
mov edi, eax |
mov eax, dword[ebp + PARTITION.FirstSector] |
mov dword[edi + XFS.FirstSector], eax |
mov eax, dword[ebp + PARTITION.FirstSector + 4] |
mov dword[edi + XFS.FirstSector + 4], eax |
mov eax, dword[ebp + PARTITION.Length] |
mov dword[edi + XFS.Length], eax |
mov eax, dword[ebp + PARTITION.Length + 4] |
mov dword[edi + XFS.Length + 4], eax |
mov eax, [ebp + PARTITION.Disk] |
mov [edi + XFS.Disk], eax |
mov [edi + XFS.FSUserFunctions], xfs_user_functions |
|
; here we initialize only one mutex so far (for the entire partition) |
; XFS potentially allows parallel r/w access to several AGs, keep it in mind for SMP times |
|
lea ecx, [edi + XFS.Lock] |
call mutex_init |
|
; read superblock and fill just allocated XFS partition structure |
|
mov eax, [ebx + xfs_sb.sb_blocksize] |
bswap eax ; XFS is big endian |
mov [edi + XFS.blocksize], eax |
movzx eax, word[ebx + xfs_sb.sb_sectsize] |
xchg al, ah |
mov [edi + XFS.sectsize], eax |
movzx eax, word[ebx + xfs_sb.sb_versionnum] |
xchg al, ah |
mov [edi + XFS.versionnum], eax |
mov eax, [ebx + xfs_sb.sb_features2] |
bswap eax |
mov [edi + XFS.features2], eax |
movzx eax, word[ebx + xfs_sb.sb_inodesize] |
xchg al, ah |
mov [edi + XFS.inodesize], eax |
movzx eax, word[ebx + xfs_sb.sb_inopblock] ; inodes per block |
xchg al, ah |
mov [edi + XFS.inopblock], eax |
movzx eax, byte[ebx + xfs_sb.sb_blocklog] ; log2 of block size, in bytes |
mov [edi + XFS.blocklog], eax |
movzx eax, byte[ebx + xfs_sb.sb_sectlog] |
mov [edi + XFS.sectlog], eax |
movzx eax, byte[ebx + xfs_sb.sb_inodelog] |
mov [edi + XFS.inodelog], eax |
movzx eax, byte[ebx + xfs_sb.sb_inopblog] |
mov [edi + XFS.inopblog], eax |
movzx eax, byte[ebx + xfs_sb.sb_dirblklog] |
mov [edi + XFS.dirblklog], eax |
mov eax, dword[ebx + xfs_sb.sb_rootino + 4] ; |
bswap eax ; big |
mov dword[edi + XFS.rootino + 0], eax ; endian |
mov eax, dword[ebx + xfs_sb.sb_rootino + 0] ; 64bit |
bswap eax ; number |
mov dword[edi + XFS.rootino + 4], eax ; |
|
mov eax, [edi + XFS.blocksize] |
mov ecx, [edi + XFS.dirblklog] |
shl eax, cl |
mov [edi + XFS.dirblocksize], eax ; blocks for files, dirblocks for directories |
|
; sector is always smaller than block |
; so precalculate shift order to allow faster sector_num->block_num conversion |
|
mov ecx, [edi + XFS.blocklog] |
sub ecx, [edi + XFS.sectlog] |
mov [edi + XFS.blockmsectlog], ecx |
|
mov eax, 1 |
shl eax, cl |
mov [edi + XFS.sectpblock], eax |
|
; shift order for inode_num->block_num conversion |
|
mov eax, [edi + XFS.blocklog] |
sub eax, [edi + XFS.inodelog] |
mov [edi + XFS.inodetoblocklog], eax |
|
mov eax, [ebx + xfs_sb.sb_agblocks] |
bswap eax |
mov [edi + XFS.agblocks], eax |
movzx ecx, byte[ebx + xfs_sb.sb_agblklog] |
mov [edi + XFS.agblklog], ecx |
|
; get the mask for block numbers |
; block numbers are AG relative! |
; bitfield length may vary between partitions |
|
mov eax, 1 |
shl eax, cl |
dec eax |
mov dword[edi + XFS.agblockmask + 0], eax |
mov eax, 1 |
sub ecx, 32 |
jc @f |
shl eax, cl |
@@: |
dec eax |
mov dword[edi + XFS.agblockmask + 4], eax |
|
; calculate magic offsets for directories |
|
mov ecx, [edi + XFS.blocklog] |
mov eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff ; lo |
mov edx, XFS_DIR2_LEAF_OFFSET SHR 32 ; hi |
shrd eax, edx, cl |
mov [edi + XFS.dir2_leaf_offset_blocks], eax |
|
mov ecx, [edi + XFS.blocklog] |
mov eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff ; lo |
mov edx, XFS_DIR2_FREE_OFFSET SHR 32 ; hi |
shrd eax, edx, cl |
mov [edi + XFS.dir2_free_offset_blocks], eax |
|
; mov ecx, [edi + XFS.dirblklog] |
; mov eax, [edi + XFS.blocksize] |
; shl eax, cl |
; mov [edi + XFS.dirblocksize], eax |
|
mov eax, [edi + XFS.blocksize] |
call malloc |
test eax, eax |
jz .error |
mov [edi + XFS.cur_block], eax |
|
; we do need XFS.blocksize bytes for single inode |
; minimal file system structure is block, inodes are packed in blocks |
|
mov eax, [edi + XFS.blocksize] |
call malloc |
test eax, eax |
jz .error |
mov [edi + XFS.cur_inode], eax |
|
; temporary inode |
; used for browsing directories |
|
mov eax, [edi + XFS.blocksize] |
call malloc |
test eax, eax |
jz .error |
mov [edi + XFS.tmp_inode], eax |
|
; current sector |
; only for sector size structures like AGI |
; inodes has usually the same size, but never store them here |
|
mov eax, [edi + XFS.sectsize] |
call malloc |
test eax, eax |
jz .error |
mov [edi + XFS.cur_sect], eax |
|
; current directory block |
|
mov eax, [edi + XFS.dirblocksize] |
call malloc |
test eax, eax |
jz .error |
mov [edi + XFS.cur_dirblock], eax |
|
.quit: |
mov eax, edi ; return pointer to allocated XFS partition structure |
pop edi esi edx ecx ebx |
ret |
.error: |
xor eax, eax |
pop edi esi edx ecx ebx |
ret |
|
|
iglobal |
align 4 |
xfs_user_functions: |
dd xfs_free |
dd (xfs_user_functions_end - xfs_user_functions - 4) / 4 |
dd xfs_Read |
dd xfs_ReadFolder |
dd 0;xfs_Rewrite |
dd 0;xfs_Write |
dd 0;xfs_SetFileEnd |
dd xfs_GetFileInfo |
dd 0;xfs_SetFileInfo |
dd 0 |
dd 0;xfs_Delete |
dd 0;xfs_CreateFolder |
xfs_user_functions_end: |
endg |
|
|
; lock partition access mutex |
proc xfs_lock |
;DEBUGF 1,"xfs_lock\n" |
lea ecx, [ebp + XFS.Lock] |
jmp mutex_lock |
endp |
|
|
; unlock partition access mutex |
proc xfs_unlock |
;DEBUGF 1,"xfs_unlock\n" |
lea ecx, [ebp + XFS.Lock] |
jmp mutex_unlock |
endp |
|
|
; free all the allocated memory |
; called on partition destroy |
proc xfs_free |
push ebp |
xchg ebp, eax |
stdcall kernel_free, [ebp + XFS.cur_block] |
stdcall kernel_free, [ebp + XFS.cur_inode] |
stdcall kernel_free, [ebp + XFS.cur_sect] |
stdcall kernel_free, [ebp + XFS.cur_dirblock] |
stdcall kernel_free, [ebp + XFS.tmp_inode] |
xchg ebp, eax |
call free |
pop ebp |
ret |
endp |
|
|
;--------------------------------------------------------------- |
; block number (AG relative) |
; eax -- inode_lo |
; edx -- inode_hi |
; ebx -- buffer |
;--------------------------------------------------------------- |
xfs_read_block: |
push ebx esi |
|
push edx |
push eax |
|
; XFS block numbers are AG relative |
; they come in bitfield form of concatenated AG and block numbers |
; to get absolute block number for fs_read32_sys we should |
; 1. extract AG number (using precalculated mask) |
; 2. multiply it by the AG size in blocks |
; 3. add AG relative block number |
|
; 1. |
mov ecx, [ebp + XFS.agblklog] |
shrd eax, edx, cl |
shr edx, cl |
; 2. |
mul dword[ebp + XFS.agblocks] |
pop ecx |
pop esi |
and ecx, dword[ebp + XFS.agblockmask + 0] |
and esi, dword[ebp + XFS.agblockmask + 4] |
; 3. |
add eax, ecx |
adc edx, esi |
|
;DEBUGF 1,"read block: 0x%x%x\n",edx,eax |
; there is no way to read file system block at once, therefore we |
; 1. calculate the number of sectors first |
; 2. and then read them in series |
|
; 1. |
mov ecx, [ebp + XFS.blockmsectlog] |
shld edx, eax, cl |
shl eax, cl |
mov esi, [ebp + XFS.sectpblock] |
|
; 2. |
.next_sector: |
push eax edx |
call fs_read32_sys |
mov ecx, eax |
pop edx eax |
test ecx, ecx |
jnz .error |
add eax, 1 ; be ready to fs_read64_sys |
adc edx, 0 |
add ebx, [ebp + XFS.sectsize] ; update buffer offset |
dec esi |
jnz .next_sector |
|
.quit: |
xor eax, eax |
pop esi ebx |
ret |
.error: |
mov eax, ecx |
pop esi ebx |
ret |
|
|
;--------------------------------------------------------------- |
; push buffer |
; push startblock_hi |
; push startblock_lo |
; call xfs_read_dirblock |
; test eax, eax |
;--------------------------------------------------------------- |
xfs_read_dirblock: |
;mov eax, [esp + 4] |
;mov edx, [esp + 8] |
;DEBUGF 1,"read dirblock at: %d %d\n",edx,eax |
;DEBUGF 1,"dirblklog: %d\n",[ebp + XFS.dirblklog] |
push ebx esi |
|
mov eax, [esp + 12] ; startblock_lo |
mov edx, [esp + 16] ; startblock_hi |
mov ebx, [esp + 20] ; buffer |
|
; dirblock >= block |
; read dirblocks by blocks |
|
mov ecx, [ebp + XFS.dirblklog] |
mov esi, 1 |
shl esi, cl |
.next_block: |
push eax edx |
call xfs_read_block |
mov ecx, eax |
pop edx eax |
test ecx, ecx |
jnz .error |
add eax, 1 ; be ready to fs_read64_sys |
adc edx, 0 |
add ebx, [ebp + XFS.blocksize] |
dec esi |
jnz .next_block |
|
.quit: |
xor eax, eax |
pop esi ebx |
ret 12 |
.error: |
mov eax, ecx |
pop esi ebx |
ret 12 |
|
|
;--------------------------------------------------------------- |
; push buffer |
; push inode_hi |
; push inode_lo |
; call xfs_read_inode |
; test eax, eax |
;--------------------------------------------------------------- |
xfs_read_inode: |
;DEBUGF 1,"reading inode: 0x%x%x\n",[esp+8],[esp+4] |
push ebx |
mov eax, [esp + 8] ; inode_lo |
mov edx, [esp + 12] ; inode_hi |
mov ebx, [esp + 16] ; buffer |
|
; inodes are packed into blocks |
; 1. calculate block number |
; 2. read the block |
; 3. add inode offset to block base address |
|
; 1. |
mov ecx, [ebp + XFS.inodetoblocklog] |
shrd eax, edx, cl |
shr edx, cl |
; 2. |
call xfs_read_block |
test eax, eax |
jnz .error |
|
; note that inode numbers should be first extracted from bitfields using mask |
|
mov eax, [esp + 8] |
mov edx, 1 |
mov ecx, [ebp + XFS.inopblog] |
shl edx, cl |
dec edx ; get inode number mask |
and eax, edx ; apply mask |
mov ecx, [ebp + XFS.inodelog] |
shl eax, cl |
add ebx, eax |
|
cmp word[ebx], XFS_DINODE_MAGIC ; test signature |
jne .error |
.quit: |
xor eax, eax |
mov edx, ebx |
pop ebx |
ret 12 |
.error: |
movi eax, ERROR_FS_FAIL |
mov edx, ebx |
pop ebx |
ret 12 |
|
|
;---------------------------------------------------------------- |
; push encoding ; ASCII / UNICODE |
; push src ; inode |
; push dst ; bdfe |
; push entries_to_read |
; push start_number ; from 0 |
;---------------------------------------------------------------- |
xfs_dir_get_bdfes: |
DEBUGF 1,"xfs_dir_get_bdfes: %d entries from %d\n",[esp+8],[esp+4] |
sub esp, 4 ; local vars |
push ecx edx esi edi |
|
mov ebx, [esp + 36] ; src |
mov edx, [esp + 32] ; dst |
mov ecx, [esp + 24] ; start_number |
|
; define directory ondisk format and jump to corresponding label |
|
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL |
jne .not_shortdir |
jmp .shortdir |
.not_shortdir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_blockdir |
mov eax, [ebx + xfs_inode.di_core.di_nextents] |
bswap eax |
cmp eax, 1 |
jne .not_blockdir |
jmp .blockdir |
.not_blockdir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_leafdir |
mov eax, [ebx + xfs_inode.di_core.di_nextents] |
bswap eax |
cmp eax, 4 |
ja .not_leafdir |
jmp .leafdir |
.not_leafdir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_nodedir |
jmp .nodedir |
.not_nodedir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE |
jne .not_btreedir |
jmp .btreedir |
.not_btreedir: |
movi eax, ERROR_FS_FAIL |
jmp .error |
|
; short form directory (all the data fits into inode) |
.shortdir: |
;DEBUGF 1,"shortdir\n", |
movzx eax, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] |
test al, al ; is count zero? |
jnz @f ; if not, use it (i8count must be zero then) |
shr eax, 8 ; use i8count |
@@: |
add eax, 1 ; '..' and '.' are implicit |
mov dword[edx + 0], 1 ; version |
mov [edx + 8], eax ; total entries |
sub eax, [esp + 24] ; start number |
cmp eax, [esp + 28] ; entries to read |
jbe @f |
mov eax, [esp + 28] |
@@: |
mov [esp + 28], eax |
mov [edx + 4], eax ; number of actually read entries |
mov [ebp + XFS.entries_read], eax |
|
; inode numbers are often saved as 4 bytes (iff they fit) |
; compute the length of inode numbers |
|
mov eax, 4 ; 4 by default |
cmp byte[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.i8count], 0 |
je @f |
add eax, eax ; 4+4=8, iff i8count != 0 |
@@: |
mov dword[edx + 12], 0 ; reserved |
mov dword[edx + 16], 0 ; |
mov dword[edx + 20], 0 ; |
mov dword[edx + 24], 0 ; |
mov dword[edx + 28], 0 ; |
add edx, 32 |
lea esi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax] |
dec ecx |
js .shortdir.fill |
|
; skip some entries if the first entry to read is not 0 |
|
.shortdir.skip: |
test ecx, ecx |
jz .shortdir.skipped |
movzx edi, byte[esi + xfs_dir2_sf_entry.namelen] |
lea esi, [esi + xfs_dir2_sf_entry.name + edi] |
add esi, eax |
dec ecx |
jnz .shortdir.skip |
mov ecx, [esp + 28] ; entries to read |
jmp .shortdir.skipped |
.shortdir.fill: |
mov ecx, [esp + 28] ; total number |
test ecx, ecx |
jz .quit |
push ecx |
;DEBUGF 1,"ecx: %d\n",ecx |
lea edi, [edx + 40] ; get file name offset |
;DEBUGF 1,"filename: ..\n" |
mov dword[edi], '..' |
mov edi, edx |
push eax ebx edx esi |
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent] |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] |
; test eax, eax |
; jnz .error |
stdcall xfs_get_inode_info, edx, edi |
test eax, eax |
pop esi edx ebx eax |
jnz .error |
mov ecx, [esp + 44] ; file name encding |
mov [edx + 4], ecx |
add edx, 304 ; ASCII only for now |
pop ecx |
dec ecx |
jz .quit |
|
; push ecx |
; lea edi, [edx + 40] |
;DEBUGF 1,"filename: .\n" |
; mov dword[edi], '.' |
; mov edi, edx |
; push eax edx |
; stdcall xfs_get_inode_info, [ebp + XFS.cur_inode], edi |
; test eax, eax |
; pop edx eax |
; jnz .error |
; mov ecx, [esp + 44] |
; mov [edx + 4], ecx |
; add edx, 304 ; ASCII only for now |
; pop ecx |
; dec ecx |
; jz .quit |
|
; we skipped some entries |
; now we fill min(required, present) number of bdfe's |
|
.shortdir.skipped: |
;DEBUGF 1,"ecx: %d\n",ecx |
push ecx |
movzx ecx, byte[esi + xfs_dir2_sf_entry.namelen] |
add esi, xfs_dir2_sf_entry.name |
lea edi, [edx + 40] ; bdfe offset of file name |
;DEBUGF 1,"filename: |%s|\n",esi |
rep movsb |
mov word[edi], 0 ; terminator (ASCIIZ) |
|
push eax ebx ecx edx esi |
; push edx ; for xfs_get_inode_info |
mov edi, edx |
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [esi + 4], [esi] |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] |
; test eax, eax |
; jnz .error |
stdcall xfs_get_inode_info, edx, edi |
test eax, eax |
pop esi edx ecx ebx eax |
jnz .error |
mov ecx, [esp + 44] ; file name encoding |
mov [edx + 4], ecx |
|
add edx, 304 ; ASCII only for now |
add esi, eax |
pop ecx |
dec ecx |
jnz .shortdir.skipped |
jmp .quit |
|
.blockdir: |
;DEBUGF 1,"blockdir\n" |
push edx |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
stdcall xfs_extent_unpack, eax |
;DEBUGF 1,"extent.br_startoff : 0x%x%x\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0] |
;DEBUGF 1,"extent.br_startblock: 0x%x%x\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0] |
;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount] |
;DEBUGF 1,"extent.br_state : %d\n",[ebp+XFS.extent.br_state] |
stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock] |
test eax, eax |
pop edx |
jnz .error |
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock] |
mov ebx, [ebp + XFS.cur_dirblock] |
mov dword[edx + 0], 1 ; version |
mov eax, [ebp + XFS.dirblocksize] |
mov ecx, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.stale] |
mov eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count] |
bswap ecx |
bswap eax |
sub eax, ecx ; actual number of entries = count - stale |
mov [edx + 8], eax ; total entries |
;DEBUGF 1,"total entries: %d\n",eax |
sub eax, [esp + 24] ; start number |
cmp eax, [esp + 28] ; entries to read |
jbe @f |
mov eax, [esp + 28] |
@@: |
mov [esp + 28], eax |
mov [edx + 4], eax ; number of actually read entries |
mov [ebp + XFS.entries_read], eax |
;DEBUGF 1,"actually read entries: %d\n",eax |
mov dword[edx + 12], 0 ; reserved |
mov dword[edx + 16], 0 ; |
mov dword[edx + 20], 0 ; |
mov dword[edx + 24], 0 ; |
mov dword[edx + 28], 0 ; |
add ebx, xfs_dir2_block.u |
|
mov ecx, [esp + 24] ; start entry number |
; also means how many to skip |
test ecx, ecx |
jz .blockdir.skipped |
.blockdir.skip: |
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG |
jne @f |
movzx eax, word[ebx + xfs_dir2_data_union.unused.length] |
xchg al, ah |
add ebx, eax |
jmp .blockdir.skip |
@@: |
movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen] |
lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 bytes for 'tag' |
add ebx, 7 ; align on 8 bytes |
and ebx, not 7 |
dec ecx |
jnz .blockdir.skip |
.blockdir.skipped: |
mov ecx, [edx + 4] ; actually read entries |
test ecx, ecx |
jz .quit |
add edx, 32 ; set edx to the first bdfe |
.blockdir.next_entry: |
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_NULL |
jne @f |
movzx eax, word[ebx + xfs_dir2_data_union.unused.length] |
xchg al, ah |
add ebx, eax |
jmp .blockdir.next_entry |
@@: |
push ecx |
push eax ebx ecx edx esi |
mov edi, edx |
mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0] |
mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4] |
bswap edx |
bswap eax |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] |
stdcall xfs_get_inode_info, edx, edi |
test eax, eax |
pop esi edx ecx ebx eax |
jnz .error |
mov ecx, [esp + 44] |
mov [edx + 4], ecx |
lea edi, [edx + 40] |
movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen] |
lea esi, [ebx + xfs_dir2_data_union.xentry.name] |
;DEBUGF 1,"filename: |%s|\n",esi |
rep movsb |
; call utf8_to_cp866 |
mov word[edi], 0 ; terminator |
lea ebx, [esi + 2] ; skip 'tag' |
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes |
and ebx, not 7 |
add edx, 304 |
pop ecx |
dec ecx |
jnz .blockdir.next_entry |
jmp .quit |
|
.leafdir: |
;DEBUGF 1,"readdir: leaf\n" |
mov [ebp + XFS.cur_inode_save], ebx |
push ebx ecx edx |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, 0xffffffff, 0xffffffff |
mov ecx, eax |
and ecx, edx |
inc ecx |
pop edx ecx ebx |
jz .error |
|
mov eax, [ebp + XFS.cur_dirblock] |
movzx ecx, word[eax + xfs_dir2_leaf.hdr.stale] |
movzx eax, word[eax + xfs_dir2_leaf.hdr.count] |
xchg cl, ch |
xchg al, ah |
sub eax, ecx |
;DEBUGF 1,"total count: %d\n",eax |
|
mov dword[edx + 0], 1 ; version |
mov [edx + 8], eax ; total entries |
sub eax, [esp + 24] ; start number |
cmp eax, [esp + 28] ; entries to read |
jbe @f |
mov eax, [esp + 28] |
@@: |
mov [esp + 28], eax |
mov [edx + 4], eax ; number of actually read entries |
|
mov dword[edx + 12], 0 ; reserved |
mov dword[edx + 16], 0 ; |
mov dword[edx + 20], 0 ; |
mov dword[edx + 24], 0 ; |
mov dword[edx + 28], 0 ; |
|
mov eax, [ebp + XFS.cur_dirblock] |
add eax, [ebp + XFS.dirblocksize] |
mov [ebp + XFS.max_dirblockaddr], eax |
mov dword[ebp + XFS.next_block_num + 0], 0 |
mov dword[ebp + XFS.next_block_num + 4], 0 |
|
mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately |
mov ecx, [esp + 24] ; start number |
test ecx, ecx |
jz .leafdir.skipped |
.leafdir.skip: |
cmp ebx, [ebp + XFS.max_dirblockaddr] |
jne @f |
push ecx edx |
mov ebx, [ebp + XFS.cur_inode_save] |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
mov ecx, eax |
and ecx, edx |
inc ecx |
jz .error |
add eax, 1 |
adc edx, 0 |
mov dword[ebp + XFS.next_block_num + 0], eax |
mov dword[ebp + XFS.next_block_num + 4], edx |
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, sizeof.xfs_dir2_data_hdr |
pop edx ecx |
@@: |
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG |
jne @f |
movzx eax, word[ebx + xfs_dir2_data_union.unused.length] |
xchg al, ah |
add ebx, eax |
jmp .leafdir.skip |
@@: |
movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen] |
lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 for 'tag' |
add ebx, 7 |
and ebx, not 7 |
dec ecx |
jnz .leafdir.skip |
.leafdir.skipped: |
mov [ebp + XFS.entries_read], 0 |
mov ecx, [edx + 4] ; actually read entries |
test ecx, ecx |
jz .quit |
add edx, 32 ; first bdfe entry |
.leafdir.next_entry: |
;DEBUGF 1,"next_extry\n" |
cmp ebx, [ebp + XFS.max_dirblockaddr] |
jne .leafdir.process_current_block |
push ecx edx |
mov ebx, [ebp + XFS.cur_inode_save] |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
mov ecx, eax |
and ecx, edx |
inc ecx |
jnz @f |
pop edx ecx |
jmp .quit |
@@: |
add eax, 1 |
adc edx, 0 |
mov dword[ebp + XFS.next_block_num + 0], eax |
mov dword[ebp + XFS.next_block_num + 4], edx |
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, sizeof.xfs_dir2_data_hdr |
pop edx ecx |
.leafdir.process_current_block: |
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG |
jne @f |
movzx eax, word[ebx + xfs_dir2_data_union.unused.length] |
xchg al, ah |
add ebx, eax |
jmp .leafdir.next_entry |
@@: |
push eax ebx ecx edx esi |
mov edi, edx |
mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0] |
mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4] |
bswap edx |
bswap eax |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] |
stdcall xfs_get_inode_info, edx, edi |
test eax, eax |
pop esi edx ecx ebx eax |
jnz .error |
push ecx |
mov ecx, [esp + 44] |
mov [edx + 4], ecx |
lea edi, [edx + 40] |
movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen] |
lea esi, [ebx + xfs_dir2_data_union.xentry.name] |
;DEBUGF 1,"filename: |%s|\n",esi |
rep movsb |
pop ecx |
mov word[edi], 0 |
lea ebx, [esi + 2] ; skip 'tag' |
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes |
and ebx, not 7 |
add edx, 304 ; ASCII only for now |
inc [ebp + XFS.entries_read] |
dec ecx |
jnz .leafdir.next_entry |
jmp .quit |
|
.nodedir: |
;DEBUGF 1,"readdir: node\n" |
push edx |
mov [ebp + XFS.cur_inode_save], ebx |
mov [ebp + XFS.entries_read], 0 |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks] |
pop edx |
test eax, eax |
jnz .error |
mov eax, [ebp + XFS.entries_read] |
mov [ebp + XFS.entries_read], 0 |
;DEBUGF 1,"numfiles: %d\n",eax |
mov dword[edx + 0], 1 ; version |
mov [edx + 8], eax ; total entries |
sub eax, [esp + 24] ; start number |
cmp eax, [esp + 28] ; entries to read |
jbe @f |
mov eax, [esp + 28] |
@@: |
mov [esp + 28], eax |
mov [edx + 4], eax ; number of actually read entries |
|
mov dword[edx + 12], 0 ; reserved |
mov dword[edx + 16], 0 ; |
mov dword[edx + 20], 0 ; |
mov dword[edx + 24], 0 ; |
mov dword[edx + 28], 0 ; |
|
mov eax, [ebp + XFS.cur_dirblock] |
add eax, [ebp + XFS.dirblocksize] |
mov [ebp + XFS.max_dirblockaddr], eax |
mov dword[ebp + XFS.next_block_num + 0], 0 |
mov dword[ebp + XFS.next_block_num + 4], 0 |
|
mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately |
mov ecx, [esp + 24] ; start number |
test ecx, ecx |
jz .leafdir.skipped |
jmp .leafdir.skip |
|
.btreedir: |
;DEBUGF 1,"readdir: btree\n" |
mov [ebp + XFS.cur_inode_save], ebx |
push ebx edx |
mov eax, [ebx + xfs_inode.di_core.di_nextents] |
bswap eax |
mov [ebp + XFS.ro_nextents], eax |
mov eax, [ebp + XFS.inodesize] |
sub eax, xfs_inode.di_u |
sub eax, sizeof.xfs_bmdr_block |
shr eax, 4 |
;DEBUGF 1,"maxnumresc: %d\n",eax |
mov edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0] |
mov eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4] |
bswap eax |
bswap edx |
mov ebx, [ebp + XFS.cur_block] |
;DEBUGF 1,"read_block: %x %x ",edx,eax |
stdcall xfs_read_block |
pop edx ebx |
test eax, eax |
jnz .error |
;DEBUGF 1,"ok\n" |
|
mov ebx, [ebp + XFS.cur_block] |
push edx |
mov [ebp + XFS.entries_read], 0 |
lea eax, [ebx + sizeof.xfs_bmbt_block] |
mov edx, [ebp + XFS.ro_nextents] |
stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks] |
pop edx |
test eax, eax |
jnz .error |
mov eax, [ebp + XFS.entries_read] |
mov [ebp + XFS.entries_read], 0 |
;DEBUGF 1,"numfiles: %d\n",eax |
|
mov dword[edx + 0], 1 ; version |
mov [edx + 8], eax ; total entries |
sub eax, [esp + 24] ; start number |
cmp eax, [esp + 28] ; entries to read |
jbe @f |
mov eax, [esp + 28] |
@@: |
mov [esp + 28], eax |
mov [edx + 4], eax ; number of actually read entries |
|
mov dword[edx + 12], 0 |
mov dword[edx + 16], 0 |
mov dword[edx + 20], 0 |
mov dword[edx + 24], 0 |
mov dword[edx + 28], 0 |
|
mov eax, [ebp + XFS.cur_dirblock] ; fsblock? |
add eax, [ebp + XFS.dirblocksize] |
mov [ebp + XFS.max_dirblockaddr], eax |
mov dword[ebp + XFS.next_block_num + 0], 0 |
mov dword[ebp + XFS.next_block_num + 4], 0 |
|
mov ebx, [ebp + XFS.max_dirblockaddr] ; to read dirblock immediately |
mov ecx, [esp + 24] ; start number |
test ecx, ecx |
jz .btreedir.skipped |
; jmp .btreedir.skip |
.btreedir.skip: |
cmp ebx, [ebp + XFS.max_dirblockaddr] |
jne @f |
push ecx edx |
mov ebx, [ebp + XFS.cur_block] |
lea eax, [ebx + sizeof.xfs_bmbt_block] |
mov edx, [ebp + XFS.ro_nextents] |
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
mov ecx, eax |
and ecx, edx |
inc ecx |
jz .error |
add eax, 1 |
adc edx, 0 |
mov dword[ebp + XFS.next_block_num + 0], eax |
mov dword[ebp + XFS.next_block_num + 4], edx |
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, sizeof.xfs_dir2_data_hdr |
pop edx ecx |
@@: |
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG |
jne @f |
movzx eax, word[ebx + xfs_dir2_data_union.unused.length] |
xchg al, ah |
add ebx, eax |
jmp .btreedir.skip |
@@: |
movzx eax, [ebx + xfs_dir2_data_union.xentry.namelen] |
lea ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2] ; 2 for 'tag' |
add ebx, 7 |
and ebx, not 7 |
dec ecx |
jnz .btreedir.skip |
.btreedir.skipped: |
mov [ebp + XFS.entries_read], 0 |
mov ecx, [edx + 4] ; actually read entries |
test ecx, ecx |
jz .quit |
add edx, 32 |
.btreedir.next_entry: |
;mov eax, [ebp + XFS.entries_read] |
;DEBUGF 1,"next_extry: %d\n",eax |
cmp ebx, [ebp + XFS.max_dirblockaddr] |
jne .btreedir.process_current_block |
push ecx edx |
mov ebx, [ebp + XFS.cur_block] |
lea eax, [ebx + sizeof.xfs_bmbt_block] |
mov edx, [ebp + XFS.ro_nextents] |
stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
mov ecx, eax |
and ecx, edx |
inc ecx |
jnz @f |
pop edx ecx |
jmp .quit |
@@: |
add eax, 1 |
adc edx, 0 |
mov dword[ebp + XFS.next_block_num + 0], eax |
mov dword[ebp + XFS.next_block_num + 4], edx |
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, sizeof.xfs_dir2_data_hdr |
pop edx ecx |
.btreedir.process_current_block: |
cmp word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG |
jne @f |
movzx eax, word[ebx + xfs_dir2_data_union.unused.length] |
xchg al, ah |
add ebx, eax |
jmp .btreedir.next_entry |
@@: |
push eax ebx ecx edx esi |
mov edi, edx |
mov edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0] |
mov eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4] |
bswap edx |
bswap eax |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode] |
stdcall xfs_get_inode_info, edx, edi |
test eax, eax |
pop esi edx ecx ebx eax |
jnz .error |
push ecx |
mov ecx, [esp + 44] |
mov [edx + 4], ecx |
lea edi, [edx + 40] |
movzx ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen] |
lea esi, [ebx + xfs_dir2_data_union.xentry.name] |
;DEBUGF 1,"filename: |%s|\n",esi |
rep movsb |
pop ecx |
mov word[edi], 0 |
lea ebx, [esi + 2] ; skip 'tag' |
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes |
and ebx, not 7 |
add edx, 304 |
inc [ebp + XFS.entries_read] |
dec ecx |
jnz .btreedir.next_entry |
jmp .quit |
|
|
.quit: |
pop edi esi edx ecx |
add esp, 4 ; pop vars |
xor eax, eax |
; mov ebx, [esp + 8] |
mov ebx, [ebp + XFS.entries_read] |
DEBUGF 1,"xfs_dir_get_bdfes done: %d\n",ebx |
ret 20 |
.error: |
pop edi esi edx ecx |
add esp, 4 ; pop vars |
mov eax, ERROR_FS_FAIL |
movi ebx, -1 |
ret 20 |
|
|
;---------------------------------------------------------------- |
; push inode_hi |
; push inode_lo |
; push name |
;---------------------------------------------------------------- |
xfs_get_inode_short: |
; this function searches for the file in _current_ dir |
; it is called recursively for all the subdirs /path/to/my/file |
|
;DEBUGF 1,"xfs_get_inode_short: %s\n",[esp+4] |
mov esi, [esp + 4] ; name |
movzx eax, word[esi] |
cmp eax, '.' ; current dir; it is already read, just return |
je .quit |
cmp eax, './' ; same thing |
je .quit |
|
; read inode |
|
mov eax, [esp + 8] ; inode_lo |
mov edx, [esp + 12] ; inode_hi |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] |
test eax, eax |
movi eax, ERROR_FS_FAIL |
jnz .error |
|
; find file name in directory |
; switch directory ondisk format |
|
mov ebx, edx |
mov [ebp + XFS.cur_inode_save], ebx |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL |
jne .not_shortdir |
;DEBUGF 1,"dir: shortdir\n" |
jmp .shortdir |
.not_shortdir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_blockdir |
mov eax, [ebx + xfs_inode.di_core.di_nextents] |
bswap eax |
cmp eax, 1 |
jne .not_blockdir |
jmp .blockdir |
.not_blockdir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_leafdir |
mov eax, [ebx + xfs_inode.di_core.di_nextents] |
bswap eax |
cmp eax, 4 |
ja .not_leafdir |
jmp .leafdir |
.not_leafdir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_nodedir |
jmp .nodedir |
.not_nodedir: |
cmp byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE |
jne .not_btreedir |
jmp .btreedir |
.not_btreedir: |
DEBUGF 1,"NOT IMPLEMENTED: DIR FORMAT\n" |
jmp .error |
|
.shortdir: |
.shortdir.check_parent: |
; parent inode number in shortform directories is always implicit, check this case |
mov eax, [esi] |
and eax, 0x00ffffff |
cmp eax, '..' |
je .shortdir.parent2 |
cmp eax, '../' |
je .shortdir.parent3 |
jmp .shortdir.common |
.shortdir.parent3: |
inc esi |
.shortdir.parent2: |
add esi, 2 |
add ebx, xfs_inode.di_u |
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_dir2_sf_hdr.count], dword[ebx + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_dir2_sf_hdr.parent] |
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax |
jmp .quit |
|
; not a parent inode? |
; search in the list, all the other files are stored uniformly |
|
.shortdir.common: |
mov eax, 4 |
movzx edx, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] ; read count (byte) and i8count (byte) at once |
test dl, dl ; is count zero? |
jnz @f |
shr edx, 8 ; use i8count |
add eax, eax ; inode_num size |
@@: |
lea edi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax] |
|
.next_name: |
movzx ecx, byte[edi + xfs_dir2_sf_entry.namelen] |
add edi, xfs_dir2_sf_entry.name |
mov esi, [esp + 4] |
;DEBUGF 1,"esi: %s\n",esi |
;DEBUGF 1,"edi: %s\n",edi |
repe cmpsb |
jne @f |
cmp byte[esi], 0 ; HINT: use adc here? |
je .found |
cmp byte[esi], '/' |
je .found_inc |
@@: |
add edi, ecx |
add edi, eax |
dec edx |
jnz .next_name |
movi eax, ERROR_FILE_NOT_FOUND |
jmp .error |
.found_inc: ; increment esi to skip '/' symbol |
; this means esi always points to valid file name or zero terminator byte |
inc esi |
.found: |
stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [edi + 4], [edi] |
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax |
jmp .quit |
|
.blockdir: |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
stdcall xfs_extent_unpack, eax |
stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock] |
test eax, eax |
jnz .error |
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock] |
mov ebx, [ebp + XFS.cur_dirblock] |
mov eax, [ebp + XFS.dirblocksize] |
mov eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count] |
; note that we don't subtract xfs_dir2_block_tail.stale here, |
; since we need the number of leaf entries rather than file number |
bswap eax |
add ebx, [ebp + XFS.dirblocksize] |
; mov ecx, sizeof.xfs_dir2_leaf_entry |
imul ecx, eax, sizeof.xfs_dir2_leaf_entry |
sub ebx, sizeof.xfs_dir2_block_tail |
sub ebx, ecx |
shr ecx, 3 |
push ecx ; for xfs_get_inode_by_hash |
push ebx ; for xfs_get_inode_by_hash |
|
mov edi, esi |
xor eax, eax |
mov ecx, 4096 ; MAX_PATH_LEN |
repne scasb |
movi eax, ERROR_FS_FAIL |
jne .error |
neg ecx |
add ecx, 4096 ; MAX_PATH_LEN |
dec ecx |
mov edx, ecx |
;DEBUGF 1,"strlen total : %d\n",edx |
mov edi, esi |
mov eax, '/' |
mov ecx, edx |
repne scasb |
jne @f |
inc ecx |
@@: |
neg ecx |
add ecx, edx |
;DEBUGF 1,"strlen current: %d\n",ecx |
stdcall xfs_hashname, esi, ecx |
add esi, ecx |
cmp byte[esi], '/' |
jne @f |
inc esi |
@@: |
;DEBUGF 1,"hashed: 0x%x\n",eax |
; bswap eax |
stdcall xfs_get_addr_by_hash |
bswap eax |
;DEBUGF 1,"got address: 0x%x\n",eax |
cmp eax, -1 |
jne @f |
movi eax, ERROR_FILE_NOT_FOUND |
mov ebx, -1 |
jmp .error |
@@: |
shl eax, 3 |
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, eax |
mov edx, [ebx + 0] |
mov eax, [ebx + 4] |
bswap edx |
bswap eax |
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax |
jmp .quit |
|
.leafdir: |
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock] |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, -1, -1 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
mov ecx, eax |
and ecx, edx |
inc ecx |
jz .error |
|
mov ebx, [ebp + XFS.cur_dirblock] |
movzx eax, [ebx + xfs_dir2_leaf.hdr.count] |
; note that we don't subtract xfs_dir2_leaf.hdr.stale here, |
; since we need the number of leaf entries rather than file number |
xchg al, ah |
add ebx, xfs_dir2_leaf.ents |
; imul ecx, eax, sizeof.xfs_dir2_leaf_entry |
; shr ecx, 3 |
push eax ; for xfs_get_addr_by_hash: len |
push ebx ; for xfs_get_addr_by_hash: base |
|
mov edi, esi |
xor eax, eax |
mov ecx, 4096 ; MAX_PATH_LEN |
repne scasb |
movi eax, ERROR_FS_FAIL |
jne .error |
neg ecx |
add ecx, 4096 |
dec ecx |
mov edx, ecx |
;DEBUGF 1,"strlen total : %d\n",edx |
mov edi, esi |
mov eax, '/' |
mov ecx, edx |
repne scasb |
jne @f |
inc ecx |
@@: |
neg ecx |
add ecx, edx |
;DEBUGF 1,"strlen current: %d\n",ecx |
stdcall xfs_hashname, esi, ecx |
add esi, ecx |
cmp byte[esi], '/' |
jne @f |
inc esi |
@@: |
;DEBUGF 1,"hashed: 0x%x\n",eax |
stdcall xfs_get_addr_by_hash |
bswap eax |
;DEBUGF 1,"got address: 0x%x\n",eax |
cmp eax, -1 |
jne @f |
movi eax, ERROR_FILE_NOT_FOUND |
mov ebx, -1 |
jmp .error |
@@: |
|
mov ebx, [ebp + XFS.cur_inode_save] |
push esi edi |
xor edi, edi |
mov esi, eax |
shld edi, esi, 3 ; get offset |
shl esi, 3 ; 2^3 = 8 byte align |
mov edx, esi |
mov ecx, [ebp + XFS.dirblklog] |
add ecx, [ebp + XFS.blocklog] |
mov eax, 1 |
shl eax, cl |
dec eax |
and edx, eax |
push edx |
shrd esi, edi, cl |
shr edi, cl |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
pop edx |
pop edi esi |
mov ecx, eax |
and ecx, edx |
inc ecx |
jz .error |
|
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, edx |
mov edx, [ebx + 0] |
mov eax, [ebx + 4] |
bswap edx |
bswap eax |
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax |
jmp .quit |
|
.nodedir: |
;DEBUGF 1,"lookupdir: node\n" |
mov [ebp + XFS.cur_inode_save], ebx |
|
mov edi, esi |
xor eax, eax |
mov ecx, 4096 ; MAX_PATH_LEN |
repne scasb |
movi eax, ERROR_FS_FAIL |
jne .error |
neg ecx |
add ecx, 4096 ; MAX_PATH_LEN |
dec ecx |
mov edx, ecx |
;DEBUGF 1,"strlen total : %d\n",edx |
mov edi, esi |
mov eax, '/' |
mov ecx, edx |
repne scasb |
jne @f |
inc ecx |
@@: |
neg ecx |
add ecx, edx |
;DEBUGF 1,"strlen current: %d\n",ecx |
stdcall xfs_hashname, esi, ecx |
add esi, ecx |
cmp byte[esi], '/' |
jne @f |
inc esi |
@@: |
;DEBUGF 1,"hashed: 0x%x\n",eax |
push edi edx |
mov edi, eax |
mov [ebp + XFS.entries_read], 0 |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi |
pop edx edi |
test eax, eax |
jnz .error |
bswap ecx |
;DEBUGF 1,"got address: 0x%x\n",ecx |
|
mov ebx, [ebp + XFS.cur_inode_save] |
push esi edi |
xor edi, edi |
mov esi, ecx |
shld edi, esi, 3 ; get offset |
shl esi, 3 ; 8 byte align |
mov edx, esi |
mov ecx, [ebp + XFS.dirblklog] |
add ecx, [ebp + XFS.blocklog] |
mov eax, 1 |
shl eax, cl |
dec eax |
and edx, eax |
push edx |
shrd esi, edi, cl |
shr edi, cl |
lea eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0] |
mov edx, [ebx + xfs_inode.di_core.di_nextents] |
bswap edx |
stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
pop edx |
pop edi esi |
mov ecx, eax |
and ecx, edx |
inc ecx |
jz .error |
|
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, edx |
mov edx, [ebx + 0] |
mov eax, [ebx + 4] |
bswap edx |
bswap eax |
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax |
jmp .quit |
|
.btreedir: |
DEBUGF 1,"lookupdir: btree\n" |
mov [ebp + XFS.cur_inode_save], ebx |
|
push ebx edx |
mov eax, [ebx + xfs_inode.di_core.di_nextents] |
bswap eax |
mov [ebp + XFS.ro_nextents], eax |
mov eax, [ebp + XFS.inodesize] |
sub eax, xfs_inode.di_u |
sub eax, sizeof.xfs_bmdr_block |
shr eax, 4 ; FIXME forkoff |
;DEBUGF 1,"maxnumresc: %d\n",eax |
mov edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0] |
mov eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4] |
bswap eax |
bswap edx |
mov ebx, [ebp + XFS.cur_block] |
;DEBUGF 1,"read_block: %x %x ",edx,eax |
stdcall xfs_read_block |
pop edx ebx |
test eax, eax |
jnz .error |
;DEBUGF 1,"ok\n" |
mov ebx, [ebp + XFS.cur_block] |
|
mov edi, esi |
xor eax, eax |
mov ecx, 4096 ; MAX_PATH_LEN |
repne scasb |
movi eax, ERROR_FS_FAIL |
jne .error |
neg ecx |
add ecx, 4096 |
dec ecx |
mov edx, ecx |
DEBUGF 1,"strlen total : %d\n",edx |
mov edi, esi |
mov eax, '/' |
mov ecx, edx |
repne scasb |
jne @f |
inc ecx |
@@: |
neg ecx |
add ecx, edx |
DEBUGF 1,"strlen current: %d\n",ecx |
stdcall xfs_hashname, esi, ecx |
add esi, ecx |
cmp byte[esi], '/' |
jne @f |
inc esi |
@@: |
DEBUGF 1,"hashed: 0x%x\n",eax |
push edi edx |
mov edi, eax |
mov [ebp + XFS.entries_read], 0 |
lea eax, [ebx + sizeof.xfs_bmbt_block] |
mov edx, [ebp + XFS.ro_nextents] |
;push eax |
;mov eax, [ebp + XFS.dir2_leaf_offset_blocks] |
;DEBUGF 1,": 0x%x %d\n",eax,eax |
;pop eax |
stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi |
pop edx edi |
test eax, eax |
jnz .error |
bswap ecx |
DEBUGF 1,"got address: 0x%x\n",ecx |
|
mov ebx, [ebp + XFS.cur_block] |
push esi edi |
xor edi, edi |
mov esi, ecx |
shld edi, esi, 3 ; get offset |
shl esi, 3 |
mov edx, esi |
mov ecx, [ebp + XFS.dirblklog] |
add ecx, [ebp + XFS.blocklog] |
mov eax, 1 |
shl eax, cl |
dec eax |
and edx, eax |
push edx |
shrd esi, edi, cl |
shr edi, cl |
lea eax, [ebx + sizeof.xfs_bmbt_block] |
mov edx, [ebp + XFS.ro_nextents] |
stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0 |
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax |
pop edx |
pop edi esi |
mov ecx, eax |
and ecx, edx |
inc ecx |
jz .error |
|
mov ebx, [ebp + XFS.cur_dirblock] |
add ebx, edx |
mov edx, [ebx + 0] |
mov eax, [ebx + 4] |
bswap edx |
bswap eax |
DEBUGF 1,"found inode: 0x%x%x\n",edx,eax |
jmp .quit |
|
.quit: |
ret 12 |
.error: |
xor eax, eax |
mov edx, eax |
ret 12 |
|
|
;---------------------------------------------------------------- |
; push name |
; call xfs_get_inode |
; test eax, eax |
;---------------------------------------------------------------- |
xfs_get_inode: |
; call xfs_get_inode_short until file is found / error returned |
|
;DEBUGF 1,"getting inode of: %s\n",[esp+4] |
push ebx esi edi |
|
; start from the root inode |
|
mov edx, dword[ebp + XFS.rootino + 4] ; hi |
mov eax, dword[ebp + XFS.rootino + 0] ; lo |
mov esi, [esp + 16] ; name |
|
.next_dir: |
cmp byte[esi], 0 |
je .found |
|
;DEBUGF 1,"next_level: |%s|\n",esi |
stdcall xfs_get_inode_short, esi, eax, edx |
test edx, edx |
jnz @f |
test eax, eax |
jz .error |
@@: |
jmp .next_dir ; file name found, go to next directory level |
|
.found: |
|
.quit: |
pop edi esi ebx |
ret 4 |
.error: |
pop edi esi ebx |
xor eax, eax |
mov edx, eax |
ret 4 |
|
|
;---------------------------------------------------------------- |
; xfs_ReadFolder - XFS implementation of reading a folder |
; in: ebp = pointer to XFS structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
xfs_ReadFolder: |
|
; to read folder |
; 1. lock partition |
; 2. find inode number |
; 3. read this inode |
; 4. get bdfe's |
; 5. unlock partition |
|
; 1. |
call xfs_lock |
push ecx edx esi edi |
|
; 2. |
push ebx esi edi |
add esi, [esp + 32] ; directory name |
;DEBUGF 1,"xfs_ReadFolder: |%s|\n",esi |
stdcall xfs_get_inode, esi |
pop edi esi ebx |
mov ecx, edx |
or ecx, eax |
jnz @f |
movi eax, ERROR_FILE_NOT_FOUND |
@@: |
|
; 3. |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] |
test eax, eax |
movi eax, ERROR_FS_FAIL |
jnz .error |
|
; 4. |
mov eax, [ebx + 8] ; encoding |
and eax, 1 |
stdcall xfs_dir_get_bdfes, [ebx + 4], [ebx + 12], [ebx + 16], edx, eax |
test eax, eax |
jnz .error |
|
.quit: |
;DEBUGF 1,"\n\n" |
pop edi esi edx ecx |
; 5. |
call xfs_unlock |
xor eax, eax |
ret |
.error: |
;DEBUGF 1,"\n\n" |
pop edi esi edx ecx |
push eax |
call xfs_unlock |
pop eax |
ret |
|
|
;---------------------------------------------------------------- |
; push inode_num_hi |
; push inode_num_lo |
; push [count] |
; call xfs_get_inode_number_sf |
;---------------------------------------------------------------- |
xfs_get_inode_number_sf: |
|
; inode numbers in short form directories may be 4 or 8 bytes long |
; determine the length in run time and read inode number at given address |
|
cmp byte[esp + 4 + xfs_dir2_sf_hdr.i8count], 0 ; i8count == 0 means 4 byte per inode number |
je .i4bytes |
.i8bytes: |
mov edx, [esp + 12] ; hi |
mov eax, [esp + 8] ; lo |
bswap edx ; big endian |
bswap eax |
ret 12 |
.i4bytes: |
xor edx, edx ; no hi |
mov eax, [esp + 12] ; hi = lo |
bswap eax ; big endian |
ret 12 |
|
|
;---------------------------------------------------------------- |
; push dest |
; push src |
; call xfs_get_inode_info |
;---------------------------------------------------------------- |
xfs_get_inode_info: |
|
; get access time and other file properties |
; useful for browsing directories |
; called for each dir entry |
|
;DEBUGF 1,"get_inode_info\n" |
xor eax, eax |
mov edx, [esp + 4] |
movzx ecx, word[edx + xfs_inode.di_core.di_mode] |
xchg cl, ch |
;DEBUGF 1,"di_mode: %x\n",ecx |
test ecx, S_IFDIR ; directory? |
jz @f |
mov eax, 0x10 ; set directory flag |
@@: |
|
mov edi, [esp + 8] |
mov [edi + 0], eax |
mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi |
bswap eax |
mov dword[edi + 36], eax ; file size hi |
;DEBUGF 1,"file_size hi: %d\n",eax |
mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo |
bswap eax |
mov dword[edi + 32], eax ; file size lo |
;DEBUGF 1,"file_size lo: %d\n",eax |
|
add edi, 8 |
mov eax, [edx + xfs_inode.di_core.di_ctime.t_sec] |
bswap eax |
push edx |
xor edx, edx |
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
pop edx |
|
mov eax, [edx + xfs_inode.di_core.di_atime.t_sec] |
bswap eax |
push edx |
xor edx, edx |
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
pop edx |
|
mov eax, [edx + xfs_inode.di_core.di_mtime.t_sec] |
bswap eax |
push edx |
xor edx, edx |
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
pop edx |
|
.quit: |
xor eax, eax |
ret 8 |
.error: |
movi eax, ERROR_FS_FAIL |
ret 8 |
|
|
;---------------------------------------------------------------- |
; push extent_data |
; call xfs_extent_unpack |
;---------------------------------------------------------------- |
xfs_extent_unpack: |
|
; extents come as packet 128bit bitfields |
; lets unpack them to access internal fields |
; write result to the XFS.extent structure |
|
push eax ebx ecx edx |
mov ebx, [esp + 20] |
|
xor eax, eax |
mov edx, [ebx + 0] |
bswap edx |
test edx, 0x80000000 ; mask, see documentation |
setnz al |
mov [ebp + XFS.extent.br_state], eax |
|
and edx, 0x7fffffff ; mask |
mov eax, [ebx + 4] |
bswap eax |
shrd eax, edx, 9 |
shr edx, 9 |
mov dword[ebp + XFS.extent.br_startoff + 0], eax |
mov dword[ebp + XFS.extent.br_startoff + 4], edx |
|
mov edx, [ebx + 4] |
mov eax, [ebx + 8] |
mov ecx, [ebx + 12] |
bswap edx |
bswap eax |
bswap ecx |
and edx, 0x000001ff ; mask |
shrd ecx, eax, 21 |
shrd eax, edx, 21 |
mov dword[ebp + XFS.extent.br_startblock + 0], ecx |
mov dword[ebp + XFS.extent.br_startblock + 4], eax |
|
mov eax, [ebx + 12] |
bswap eax |
and eax, 0x001fffff ; mask |
mov [ebp + XFS.extent.br_blockcount], eax |
|
pop edx ecx ebx eax |
;DEBUGF 1,"extent.br_startoff : %d %d\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0] |
;DEBUGF 1,"extent.br_startblock: %d %d\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0] |
;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount] |
;DEBUGF 1,"extent.br_state : %d\n",[ebp+XFS.extent.br_state] |
ret 4 |
|
|
;---------------------------------------------------------------- |
; push namelen |
; push name |
; call xfs_hashname |
;---------------------------------------------------------------- |
xfs_hashname: ; xfs_da_hashname |
|
; simple hash function |
; never fails) |
|
push ecx esi |
xor eax, eax |
mov esi, [esp + 12] ; name |
mov ecx, [esp + 16] ; namelen |
;mov esi, '.' |
;mov ecx, 1 |
;DEBUGF 1,"hashname: %d %s\n",ecx,esi |
|
@@: |
rol eax, 7 |
xor al, [esi] |
add esi, 1 |
loop @b |
|
pop esi ecx |
ret 8 |
|
|
;---------------------------------------------------------------- |
; push len |
; push base |
; eax -- hash value |
; call xfs_get_addr_by_hash |
;---------------------------------------------------------------- |
xfs_get_addr_by_hash: |
|
; look for the directory entry offset by its file name hash |
; allows fast file search for block, leaf and node directories |
; binary (ternary) search |
|
;DEBUGF 1,"get_addr_by_hash\n" |
push ebx esi |
mov ebx, [esp + 12] ; left |
mov edx, [esp + 16] ; len |
.next: |
mov ecx, edx |
; jecxz .error |
test ecx, ecx |
jz .error |
shr ecx, 1 |
mov esi, [ebx + ecx*8 + xfs_dir2_leaf_entry.hashval] |
bswap esi |
;DEBUGF 1,"cmp 0x%x",esi |
cmp eax, esi |
jb .below |
ja .above |
mov eax, [ebx + ecx*8 + xfs_dir2_leaf_entry.address] |
pop esi ebx |
ret 8 |
.below: |
;DEBUGF 1,"b\n" |
mov edx, ecx |
jmp .next |
.above: |
;DEBUGF 1,"a\n" |
lea ebx, [ebx + ecx*8 + 8] |
sub edx, ecx |
dec edx |
jmp .next |
.error: |
mov eax, -1 |
pop esi ebx |
ret 8 |
|
|
;---------------------------------------------------------------- |
; xfs_GetFileInfo - XFS implementation of getting file info |
; in: ebp = pointer to XFS structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
xfs_GetFileInfo: |
|
; lock partition |
; get inode number by file name |
; read inode |
; get info |
; unlock partition |
|
push ecx edx esi edi |
call xfs_lock |
|
add esi, [esp + 20] ; name |
;DEBUGF 1,"xfs_GetFileInfo: |%s|\n",esi |
stdcall xfs_get_inode, esi |
mov ecx, edx |
or ecx, eax |
jnz @f |
movi eax, ERROR_FILE_NOT_FOUND |
jmp .error |
@@: |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] |
test eax, eax |
movi eax, ERROR_FS_FAIL |
jnz .error |
|
stdcall xfs_get_inode_info, edx, [ebx + 16] |
|
.quit: |
call xfs_unlock |
pop edi esi edx ecx |
xor eax, eax |
;DEBUGF 1,"quit\n\n" |
ret |
.error: |
call xfs_unlock |
pop edi esi edx ecx |
;DEBUGF 1,"error\n\n" |
ret |
|
|
;---------------------------------------------------------------- |
; xfs_Read - XFS implementation of reading a file |
; in: ebp = pointer to XFS structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
xfs_Read: |
push ebx ecx edx esi edi |
call xfs_lock |
|
add esi, [esp + 24] |
;DEBUGF 1,"xfs_Read: %d %d |%s|\n",[ebx+4],[ebx+12],esi |
stdcall xfs_get_inode, esi |
mov ecx, edx |
or ecx, eax |
jnz @f |
movi eax, ERROR_FILE_NOT_FOUND |
jmp .error |
@@: |
stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode] |
test eax, eax |
movi eax, ERROR_FS_FAIL |
jnz .error |
mov [ebp + XFS.cur_inode_save], edx |
|
cmp byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS |
jne .not_extent_list |
jmp .extent_list |
.not_extent_list: |
cmp byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE |
jne .not_btree |
jmp .btree |
.not_btree: |
DEBUGF 1,"XFS: NOT IMPLEMENTED: FILE FORMAT\n" |
movi eax, ERROR_FS_FAIL |
jmp .error |
.extent_list: |
mov ecx, [ebx + 12] ; bytes to read |
mov edi, [ebx + 16] ; buffer for data |
mov esi, [ebx + 8] ; offset_hi |
mov ebx, [ebx + 4] ; offset_lo |
|
mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo |
bswap eax |
mov dword[ebp + XFS.bytes_left_in_file + 0], eax ; lo |
mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi |
bswap eax |
mov dword[ebp + XFS.bytes_left_in_file + 4], eax ; hi |
|
mov eax, [edx + xfs_inode.di_core.di_nextents] |
bswap eax |
mov [ebp + XFS.left_extents], eax |
|
mov dword[ebp + XFS.bytes_read], 0 ; actually read bytes |
|
xor eax, eax ; extent offset in list |
.extent_list.next_extent: |
;DEBUGF 1,"extent_list.next_extent, eax: 0x%x\n",eax |
;DEBUGF 1,"bytes_to_read: %d\n",ecx |
;DEBUGF 1,"cur file offset: %d %d\n",esi,ebx |
;DEBUGF 1,"esp: 0x%x\n",esp |
cmp [ebp + XFS.left_extents], 0 |
jne @f |
test ecx, ecx |
jz .quit |
movi eax, ERROR_END_OF_FILE |
jmp .error |
@@: |
push eax |
lea eax, [edx + xfs_inode.di_u + eax + xfs_bmbt_rec.l0] |
stdcall xfs_extent_unpack, eax |
pop eax |
dec [ebp + XFS.left_extents] |
add eax, sizeof.xfs_bmbt_rec |
push eax ebx ecx edx esi |
mov ecx, [ebp + XFS.blocklog] |
shrd ebx, esi, cl |
shr esi, cl |
cmp esi, dword[ebp + XFS.extent.br_startoff + 4] |
jb .extent_list.to_hole ; handle sparse files |
ja @f |
cmp ebx, dword[ebp + XFS.extent.br_startoff + 0] |
jb .extent_list.to_hole ; handle sparse files |
je .extent_list.to_extent ; read from the start of current extent |
@@: |
xor edx, edx |
mov eax, [ebp + XFS.extent.br_blockcount] |
add eax, dword[ebp + XFS.extent.br_startoff + 0] |
adc edx, dword[ebp + XFS.extent.br_startoff + 4] |
;DEBUGF 1,"br_startoff: %d %d\n",edx,eax |
cmp esi, edx |
ja .extent_list.skip_extent |
jb .extent_list.to_extent |
cmp ebx, eax |
jae .extent_list.skip_extent |
jmp .extent_list.to_extent |
.extent_list.to_hole: |
;DEBUGF 1,"extent_list.to_hole\n" |
pop esi edx ecx ebx eax |
jmp .extent_list.read_hole |
.extent_list.to_extent: |
;DEBUGF 1,"extent_list.to_extent\n" |
pop esi edx ecx ebx eax |
jmp .extent_list.read_extent |
.extent_list.skip_extent: |
;DEBUGF 1,"extent_list.skip_extent\n" |
pop esi edx ecx ebx eax |
jmp .extent_list.next_extent |
|
.extent_list.read_hole: |
;DEBUGF 1,"hole: offt: 0x%x%x ",esi,ebx |
push eax edx |
mov eax, dword[ebp + XFS.extent.br_startoff + 0] |
mov edx, dword[ebp + XFS.extent.br_startoff + 4] |
push esi ebx |
mov ebx, ecx |
sub eax, ebx ; get hole_size, it is 64 bit |
sbb edx, 0 ; now edx:eax contains the size of hole |
;DEBUGF 1,"size: 0x%x%x\n",edx,eax |
jnz @f ; if hole size >= 2^32, write bytes_to_read zero bytes |
cmp eax, ecx ; if hole size >= bytes_to_read, write bytes_to_read zeros |
jae @f |
mov ecx, eax ; if hole is < than bytes_to_read, write hole size zeros |
@@: |
sub ebx, ecx ; bytes_to_read - hole_size = left_to_read |
add dword[esp + 0], ecx ; update pushed file offset |
adc dword[esp + 4], 0 |
xor eax, eax ; hole is made of zeros |
rep stosb |
mov ecx, ebx |
pop ebx esi |
|
test ecx, ecx ; all requested bytes are read? |
pop edx eax |
jz .quit |
jmp .extent_list.read_extent ; continue from the start of unpacked extent |
|
.extent_list.read_extent: |
;DEBUGF 1,"extent_list.read_extent\n" |
push eax ebx ecx edx esi |
mov eax, ebx |
mov edx, esi |
mov ecx, [ebp + XFS.blocklog] |
shrd eax, edx, cl |
shr edx, cl |
sub eax, dword[ebp + XFS.extent.br_startoff + 0] ; skip esi:ebx ? |
sbb edx, dword[ebp + XFS.extent.br_startoff + 4] |
sub [ebp + XFS.extent.br_blockcount], eax |
add dword[ebp + XFS.extent.br_startblock + 0], eax |
adc dword[ebp + XFS.extent.br_startblock + 4], 0 |
.extent_list.read_extent.next_block: |
;DEBUGF 1,"extent_list.read_extent.next_block\n" |
cmp [ebp + XFS.extent.br_blockcount], 0 ; out of blocks in current extent? |
jne @f |
pop esi edx ecx ebx eax |
jmp .extent_list.next_extent ; go to next extent |
@@: |
mov eax, dword[ebp + XFS.extent.br_startblock + 0] |
mov edx, dword[ebp + XFS.extent.br_startblock + 4] |
push ebx |
mov ebx, [ebp + XFS.cur_block] |
;DEBUGF 1,"read block: 0x%x%x\n",edx,eax |
stdcall xfs_read_block |
test eax, eax |
pop ebx |
jz @f |
pop esi edx ecx ebx eax |
movi eax, ERROR_FS_FAIL |
jmp .error |
@@: |
dec [ebp + XFS.extent.br_blockcount] |
add dword[ebp + XFS.extent.br_startblock + 0], 1 |
adc dword[ebp + XFS.extent.br_startblock + 4], 0 |
mov esi, [ebp + XFS.cur_block] |
mov ecx, [ebp + XFS.blocklog] |
mov eax, 1 |
shl eax, cl |
dec eax ; get blocklog mask |
and eax, ebx ; offset in current block |
add esi, eax |
neg eax |
add eax, [ebp + XFS.blocksize] |
mov ecx, [esp + 8] ; pushed ecx, bytes_to_read |
cmp ecx, eax ; is current block enough? |
jbe @f ; if so, read bytes_to_read bytes |
mov ecx, eax ; otherwise read the block up to the end |
@@: |
sub [esp + 8], ecx ; left_to_read |
add [esp + 12], ecx ; update current file offset, pushed ebx |
sub dword[ebp + XFS.bytes_left_in_file + 0], ecx |
sbb dword[ebp + XFS.bytes_left_in_file + 4], 0 |
jnc @f |
add dword[ebp + XFS.bytes_left_in_file + 0], ecx |
mov ecx, dword[ebp + XFS.bytes_left_in_file + 0] |
mov dword[ebp + XFS.bytes_left_in_file + 0], 0 |
mov dword[ebp + XFS.bytes_left_in_file + 4], 0 |
@@: |
add [ebp + XFS.bytes_read], ecx |
adc [esp + 0], dword 0 ; pushed esi |
;DEBUGF 1,"read data: %d\n",ecx |
rep movsb |
mov ecx, [esp + 8] |
;DEBUGF 1,"left_to_read: %d\n",ecx |
xor ebx, ebx |
test ecx, ecx |
jz @f |
cmp dword[ebp + XFS.bytes_left_in_file + 4], 0 |
jne .extent_list.read_extent.next_block |
cmp dword[ebp + XFS.bytes_left_in_file + 0], 0 |
jne .extent_list.read_extent.next_block |
@@: |
pop esi edx ecx ebx eax |
jmp .quit |
|
.btree: |
mov ecx, [ebx + 12] ; bytes to read |
mov [ebp + XFS.bytes_to_read], ecx |
mov edi, [ebx + 16] ; buffer for data |
mov esi, [ebx + 8] ; offset_hi |
mov ebx, [ebx + 4] ; offset_lo |
mov dword[ebp + XFS.file_offset + 0], ebx |
mov dword[ebp + XFS.file_offset + 4], esi |
mov [ebp + XFS.buffer_pos], edi |
|
mov eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo |
bswap eax |
mov dword[ebp + XFS.bytes_left_in_file + 0], eax ; lo |
mov eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi |
bswap eax |
mov dword[ebp + XFS.bytes_left_in_file + 4], eax ; hi |
|
mov eax, [edx + xfs_inode.di_core.di_nextents] |
bswap eax |
mov [ebp + XFS.left_extents], eax |
|
mov dword[ebp + XFS.bytes_read], 0 ; actually read bytes |
|
push ebx ecx edx esi edi |
mov [ebp + XFS.eof], 0 |
mov eax, dword[ebp + XFS.file_offset + 0] |
mov edx, dword[ebp + XFS.file_offset + 4] |
add eax, [ebp + XFS.bytes_to_read] |
adc edx, 0 |
sub eax, dword[ebp + XFS.bytes_left_in_file + 0] |
sbb edx, dword[ebp + XFS.bytes_left_in_file + 4] |
jc @f ; file_offset + bytes_to_read < file_size |
jz @f ; file_offset + bytes_to_read = file_size |
mov [ebp + XFS.eof], 1 |
cmp edx, 0 |
jne .error.eof |
sub dword[ebp + XFS.bytes_to_read], eax |
jc .error.eof |
jz .error.eof |
@@: |
stdcall xfs_btree_read, 0, 0, 1 |
pop edi esi edx ecx ebx |
test eax, eax |
jnz .error |
cmp [ebp + XFS.eof], 1 |
jne .quit |
jmp .error.eof |
|
|
.quit: |
call xfs_unlock |
pop edi esi edx ecx ebx |
xor eax, eax |
mov ebx, [ebp + XFS.bytes_read] |
;DEBUGF 1,"quit: %d\n\n",ebx |
ret |
.error.eof: |
movi eax, ERROR_END_OF_FILE |
.error: |
;DEBUGF 1,"error\n\n" |
call xfs_unlock |
pop edi esi edx ecx ebx |
mov ebx, [ebp + XFS.bytes_read] |
ret |
|
|
;---------------------------------------------------------------- |
; push max_offset_hi |
; push max_offset_lo |
; push nextents |
; push block_number_hi |
; push block_number_lo |
; push extent_list |
; -1 / read block number |
;---------------------------------------------------------------- |
xfs_extent_list_read_dirblock: ; skips holes |
;DEBUGF 1,"xfs_extent_list_read_dirblock\n" |
push ebx esi edi |
;mov eax, [esp+28] |
;DEBUGF 1,"nextents: %d\n",eax |
;mov eax, [esp+20] |
;mov edx, [esp+24] |
;DEBUGF 1,"block_number: 0x%x%x\n",edx,eax |
;mov eax, [esp+32] |
;mov edx, [esp+36] |
;DEBUGF 1,"max_addr : 0x%x%x\n",edx,eax |
mov ebx, [esp + 16] |
mov esi, [esp + 20] |
mov edi, [esp + 24] |
; mov ecx, [esp + 28] ; nextents |
.next_extent: |
;DEBUGF 1,"next_extent\n" |
dec dword[esp + 28] |
js .error |
stdcall xfs_extent_unpack, ebx |
add ebx, sizeof.xfs_bmbt_rec ; next extent |
mov edx, dword[ebp + XFS.extent.br_startoff + 4] |
mov eax, dword[ebp + XFS.extent.br_startoff + 0] |
cmp edx, [esp + 36] ; max_offset_hi |
ja .error |
jb @f |
cmp eax, [esp + 32] ; max_offset_lo |
jae .error |
@@: |
cmp edi, edx |
jb .hole |
ja .check_count |
cmp esi, eax |
jb .hole |
ja .check_count |
jmp .read_block |
.hole: |
;DEBUGF 1,"hole\n" |
mov esi, eax |
mov edi, edx |
jmp .read_block |
.check_count: |
;DEBUGF 1,"check_count\n" |
add eax, [ebp + XFS.extent.br_blockcount] |
adc edx, 0 |
cmp edi, edx |
ja .next_extent |
jb .read_block |
cmp esi, eax |
jae .next_extent |
; jmp .read_block |
.read_block: |
;DEBUGF 1,"read_block\n" |
push esi edi |
sub esi, dword[ebp + XFS.extent.br_startoff + 0] |
sbb edi, dword[ebp + XFS.extent.br_startoff + 4] |
add esi, dword[ebp + XFS.extent.br_startblock + 0] |
adc edi, dword[ebp + XFS.extent.br_startblock + 4] |
stdcall xfs_read_dirblock, esi, edi, [ebp + XFS.cur_dirblock] |
pop edx eax |
.quit: |
;DEBUGF 1,"xfs_extent_list_read_dirblock: quit\n" |
pop edi esi ebx |
ret 24 |
.error: |
;DEBUGF 1,"xfs_extent_list_read_dirblock: error\n" |
xor eax, eax |
dec eax |
mov edx, eax |
pop edi esi ebx |
ret 24 |
|
|
;---------------------------------------------------------------- |
; push dirblock_num |
; push nextents |
; push extent_list |
;---------------------------------------------------------------- |
xfs_dir2_node_get_numfiles: |
|
; unfortunately, we need to set 'total entries' field |
; this often requires additional effort, since there is no such a number in most directory ondisk formats |
|
;DEBUGF 1,"xfs_dir2_node_get_numfiles\n" |
push ebx ecx edx esi edi |
|
mov eax, [esp + 24] |
mov edx, [esp + 28] |
mov esi, [esp + 32] |
stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1 |
mov ecx, eax |
and ecx, edx |
inc ecx |
jnz @f |
movi eax, ERROR_FS_FAIL |
jmp .error |
@@: |
mov ebx, [ebp + XFS.cur_dirblock] |
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC |
je .node |
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC |
je .leaf |
mov eax, ERROR_FS_FAIL |
jmp .error |
|
.node: |
;DEBUGF 1,".node\n" |
mov edi, [ebx + xfs_da_intnode.hdr.info.forw] |
bswap edi |
mov eax, [esp + 24] |
mov edx, [esp + 28] |
mov esi, [ebx + xfs_da_intnode.btree.before] |
bswap esi |
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi |
test eax, eax |
jnz .error |
jmp .common |
|
.leaf: |
;DEBUGF 1,".leaf\n" |
movzx ecx, word[ebx + xfs_dir2_leaf.hdr.count] |
xchg cl, ch |
movzx eax, word[ebx + xfs_dir2_leaf.hdr.stale] |
xchg al, ah |
sub ecx, eax |
add [ebp + XFS.entries_read], ecx |
mov edi, [ebx + xfs_dir2_leaf.hdr.info.forw] |
bswap edi |
jmp .common |
|
.common: |
test edi, edi |
jz .quit |
mov esi, edi |
mov eax, [esp + 24] |
mov edx, [esp + 28] |
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi |
test eax, eax |
jnz .error |
jmp .quit |
|
.quit: |
;DEBUGF 1,".quit\n" |
pop edi esi edx ecx ebx |
xor eax, eax |
ret 12 |
.error: |
;DEBUGF 1,".error\n" |
pop edi esi edx ecx ebx |
movi eax, ERROR_FS_FAIL |
ret 12 |
|
|
;---------------------------------------------------------------- |
; push hash |
; push dirblock_num |
; push nextents |
; push extent_list |
;---------------------------------------------------------------- |
xfs_dir2_lookupdir_node: |
DEBUGF 1,"xfs_dir2_lookupdir_node\n" |
push ebx edx esi edi |
|
mov eax, [esp + 20] |
mov edx, [esp + 24] |
mov esi, [esp + 28] |
DEBUGF 1,"read dirblock: 0x%x %d\n",esi,esi |
stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1 |
DEBUGF 1,"dirblock read: 0x%x%x\n",edx,eax |
mov ecx, eax |
and ecx, edx |
inc ecx |
jnz @f |
movi eax, ERROR_FS_FAIL |
jmp .error |
@@: |
DEBUGF 1,"checkpoint #1\n" |
mov ebx, [ebp + XFS.cur_dirblock] |
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC |
je .node |
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC |
je .leaf |
mov eax, ERROR_FS_FAIL |
DEBUGF 1,"checkpoint #2\n" |
jmp .error |
|
.node: |
DEBUGF 1,".node\n" |
mov edi, [esp + 32] ; hash |
movzx ecx, word[ebx + xfs_da_intnode.hdr.count] |
xchg cl, ch |
mov [ebp + XFS.left_leaves], ecx |
xor ecx, ecx |
.node.next_leaf: |
mov esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.hashval] |
bswap esi |
cmp edi, esi |
jbe .node.leaf_found |
inc ecx |
cmp ecx, [ebp + XFS.left_leaves] |
jne .node.next_leaf |
mov eax, ERROR_FILE_NOT_FOUND |
jmp .error |
@@: |
.node.leaf_found: |
mov eax, [esp + 20] |
mov edx, [esp + 24] |
mov esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.before] |
bswap esi |
stdcall xfs_dir2_lookupdir_node, eax, edx, esi, edi |
test eax, eax |
jz .quit |
movi eax, ERROR_FILE_NOT_FOUND |
jmp .error |
|
.leaf: |
DEBUGF 1,".leaf\n" |
movzx ecx, [ebx + xfs_dir2_leaf.hdr.count] |
xchg cl, ch |
lea esi, [ebx + xfs_dir2_leaf.ents] |
mov eax, [esp + 32] |
stdcall xfs_get_addr_by_hash, esi, ecx |
cmp eax, -1 |
je .error |
mov ecx, eax |
jmp .quit |
|
.quit: |
DEBUGF 1,".quit\n" |
pop edi esi edx ebx |
xor eax, eax |
ret 16 |
.error: |
DEBUGF 1,".error\n" |
pop edi esi edx ebx |
ret 16 |
|
|
;---------------------------------------------------------------- |
; push dirblock_num |
; push nextents |
; push extent_list |
;---------------------------------------------------------------- |
xfs_dir2_btree_get_numfiles: |
;DEBUGF 1,"xfs_dir2_node_get_numfiles\n" |
push ebx ecx edx esi edi |
|
mov eax, [esp + 24] |
mov edx, [esp + 28] |
mov esi, [esp + 32] |
stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1 |
mov ecx, eax |
and ecx, edx |
inc ecx |
jnz @f |
movi eax, ERROR_FS_FAIL |
jmp .error |
@@: |
mov ebx, [ebp + XFS.cur_dirblock] |
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC |
je .node |
cmp word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC |
je .leaf |
mov eax, ERROR_FS_FAIL |
jmp .error |
|
.node: |
;DEBUGF 1,".node\n" |
mov edi, [ebx + xfs_da_intnode.hdr.info.forw] |
bswap edi |
mov eax, [esp + 24] |
mov edx, [esp + 28] |
mov esi, [ebx + xfs_da_intnode.btree.before] |
bswap esi |
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi |
test eax, eax |
jnz .error |
jmp .common |
|
.leaf: |
;DEBUGF 1,".leaf\n" |
movzx ecx, word[ebx + xfs_dir2_leaf.hdr.count] |
xchg cl, ch |
movzx eax, word[ebx + xfs_dir2_leaf.hdr.stale] |
xchg al, ah |
sub ecx, eax |
add [ebp + XFS.entries_read], ecx |
mov edi, [ebx + xfs_dir2_leaf.hdr.info.forw] |
bswap edi |
jmp .common |
|
.common: |
test edi, edi |
jz .quit |
mov esi, edi |
mov eax, [esp + 24] |
mov edx, [esp + 28] |
stdcall xfs_dir2_node_get_numfiles, eax, edx, esi |
test eax, eax |
jnz .error |
jmp .quit |
|
.quit: |
;DEBUGF 1,".quit\n" |
pop edi esi edx ecx ebx |
xor eax, eax |
ret 12 |
.error: |
;DEBUGF 1,".error\n" |
pop edi esi edx ecx ebx |
movi eax, ERROR_FS_FAIL |
ret 12 |
|
|
;---------------------------------------------------------------- |
; push is_root |
; push block_hi |
; push block_lo |
;---------------------------------------------------------------- |
xfs_btree_read: |
push ebx ecx edx esi edi |
cmp dword[esp + 32], 1 ; is root? |
je .root |
jmp .not_root |
.root: |
DEBUGF 1,".root\n" |
mov ebx, [ebp + XFS.cur_inode_save] |
add ebx, xfs_inode.di_u |
movzx edx, [ebx + xfs_bmdr_block.bb_numrecs] |
xchg dl, dh |
dec edx |
add ebx, sizeof.xfs_bmdr_block |
xor eax, eax |
dec eax |
.root.next_key: |
DEBUGF 1,".root.next_key\n" |
cmp [ebp + XFS.bytes_to_read], 0 |
je .quit |
inc eax |
cmp eax, edx ; out of keys? |
ja .root.key_found ; there is no length field, so try the last key |
lea edi, [ebx + sizeof.xfs_bmbt_key*eax + 0] |
lea esi, [ebx + sizeof.xfs_bmbt_key*eax + 4] |
bswap edi |
bswap esi |
mov ecx, [ebp + XFS.blocklog] |
shld edi, esi, cl |
shl esi, cl |
cmp edi, dword[ebp + XFS.file_offset + 4] |
ja .root.prev_or_hole |
jb .root.next_key |
cmp esi, dword[ebp + XFS.file_offset + 0] |
ja .root.prev_or_hole |
jb .root.next_key |
jmp .root.key_found |
.root.prev_or_hole: |
DEBUGF 1,".root.prev_or_hole\n" |
test eax, eax |
jz .root.hole |
dec eax |
jmp .root.key_found |
.root.hole: |
DEBUGF 1,".root.hole\n" |
push eax edx esi edi |
mov ecx, [ebp + XFS.blocklog] |
shld edi, esi, cl |
shl esi, cl |
sub esi, dword[ebp + XFS.file_offset + 0] |
sbb edi, dword[ebp + XFS.file_offset + 4] |
mov ecx, [ebp + XFS.bytes_to_read] |
cmp edi, 0 ; hole size >= 2^32 |
jne @f |
cmp ecx, esi |
jbe @f |
mov ecx, esi |
@@: |
add dword[ebp + XFS.file_offset + 0], ecx |
adc dword[ebp + XFS.file_offset + 4], 0 |
sub [ebp + XFS.bytes_to_read], ecx |
xor eax, eax |
mov edi, [ebp + XFS.buffer_pos] |
rep stosb |
mov [ebp + XFS.buffer_pos], edi |
pop edi esi edx eax |
jmp .root.next_key |
.root.key_found: |
DEBUGF 1,".root.key_found\n" |
mov edx, [ebp + XFS.cur_inode_save] |
mov eax, [ebp + XFS.inodesize] |
sub eax, xfs_inode.di_u |
cmp [edx + xfs_inode.di_core.di_forkoff], 0 |
je @f |
movzx eax, [edx + xfs_inode.di_core.di_forkoff] |
shl eax, XFS_DIR2_DATA_ALIGN_LOG ; 3 |
@@: |
sub eax, sizeof.xfs_bmdr_block |
shr eax, 4 ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr) |
mov edx, [ebx + sizeof.xfs_bmbt_key*eax + 0] ; hi |
mov eax, [ebx + sizeof.xfs_bmbt_key*eax + 4] ; hi |
bswap edx |
bswap eax |
stdcall xfs_btree_read, eax, edx, 0 |
test eax, eax |
jnz .error |
jmp .root.next_key |
|
.not_root: |
DEBUGF 1,".root.not_root\n" |
mov eax, [esp + 24] ; block_lo |
mov edx, [esp + 28] ; block_hi |
mov ebx, [ebp + XFS.cur_block] |
stdcall xfs_read_block |
test eax, eax |
jnz .error |
mov ebx, [ebp + XFS.cur_block] |
|
cmp [ebx + xfs_bmbt_block.bb_magic], XFS_BMAP_MAGIC |
jne .error |
cmp [ebx + xfs_bmbt_block.bb_level], 0 ; leaf? |
je .leaf |
jmp .node |
|
.node: |
; mov eax, [ebp + XFS.blocksize] |
; sub eax, sizeof.xfs_bmbt_block |
; shr eax, 4 ; maxnumrecs |
mov eax, dword[ebp + XFS.file_offset + 0] ; lo |
mov edx, dword[ebp + XFS.file_offset + 4] ; hi |
movzx edx, [ebx + xfs_bmbt_block.bb_numrecs] |
xchg dl, dh |
dec edx |
add ebx, sizeof.xfs_bmbt_block |
xor eax, eax |
dec eax |
.node.next_key: |
push eax ecx edx esi edi |
mov eax, [esp + 44] ; block_lo |
mov edx, [esp + 48] ; block_hi |
mov ebx, [ebp + XFS.cur_block] |
stdcall xfs_read_block |
test eax, eax |
jnz .error |
mov ebx, [ebp + XFS.cur_block] |
add ebx, sizeof.xfs_bmbt_block |
pop edi esi edx ecx eax |
cmp [ebp + XFS.bytes_to_read], 0 |
je .quit |
inc eax |
cmp eax, edx ; out of keys? |
ja .node.key_found ; there is no length field, so try the last key |
lea edi, [ebx + sizeof.xfs_bmbt_key*eax + 0] |
lea esi, [ebx + sizeof.xfs_bmbt_key*eax + 4] |
bswap edi |
bswap esi |
mov ecx, [ebp + XFS.blocklog] |
shld edi, esi, cl |
shl esi, cl |
cmp edi, dword[ebp + XFS.file_offset + 4] |
ja .node.prev_or_hole |
jb .node.next_key |
cmp esi, dword[ebp + XFS.file_offset + 0] |
ja .node.prev_or_hole |
jb .node.next_key |
jmp .node.key_found |
.node.prev_or_hole: |
test eax, eax |
jz .node.hole |
dec eax |
jmp .node.key_found |
.node.hole: |
push eax edx esi edi |
mov ecx, [ebp + XFS.blocklog] |
shld edi, esi, cl |
shl esi, cl |
sub esi, dword[ebp + XFS.file_offset + 0] |
sbb edi, dword[ebp + XFS.file_offset + 4] |
mov ecx, [ebp + XFS.bytes_to_read] |
cmp edi, 0 ; hole size >= 2^32 |
jne @f |
cmp ecx, esi |
jbe @f |
mov ecx, esi |
@@: |
add dword[ebp + XFS.file_offset + 0], ecx |
adc dword[ebp + XFS.file_offset + 4], 0 |
sub [ebp + XFS.bytes_to_read], ecx |
xor eax, eax |
mov edi, [ebp + XFS.buffer_pos] |
rep stosb |
mov [ebp + XFS.buffer_pos], edi |
pop edi esi edx eax |
jmp .node.next_key |
.node.key_found: |
mov edx, [ebp + XFS.cur_inode_save] |
mov eax, [ebp + XFS.inodesize] |
sub eax, xfs_inode.di_u |
cmp [edx + xfs_inode.di_core.di_forkoff], 0 |
je @f |
movzx eax, [edx + xfs_inode.di_core.di_forkoff] |
shl eax, XFS_DIR2_DATA_ALIGN_LOG ; 3 |
@@: |
sub eax, sizeof.xfs_bmdr_block |
shr eax, 4 ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr) |
mov edx, [ebx + sizeof.xfs_bmbt_key*eax + 0] ; hi |
mov eax, [ebx + sizeof.xfs_bmbt_key*eax + 4] ; hi |
bswap edx |
bswap eax |
stdcall xfs_btree_read, eax, edx, 0 |
test eax, eax |
jnz .error |
jmp .node.next_key |
jmp .quit |
|
.leaf: |
|
jmp .quit |
|
.error: |
pop edi esi edx ecx ebx |
movi eax, ERROR_FS_FAIL |
ret 4 |
.quit: |
pop edi esi edx ecx ebx |
xor eax, eax |
ret 4 |
|
|
;---------------------------------------------------------------- |
; push nextents |
; push extent_list |
; push file_offset_hi |
; push file_offset_lo |
;---------------------------------------------------------------- |
;xfs_extent_list_read: |
; push ebx 0 edx esi edi ; zero means actually_read_bytes |
; |
; .quit: |
; pop edi esi edx ecx ebx |
; xor eax, eax |
; ret 24 |
; .error: |
; pop edi esi edx ecx ebx |
; ret 24 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |