Subversion Repositories Kolibri OS

Rev

Rev 9890 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2013-2022. All rights reserved. ;;
  4. ;;  Distributed under terms of the GNU General Public License   ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 10007 $
  9.  
  10.  
  11. include 'xfs.inc'
  12.  
  13. macro omit_frame_pointer_prologue procname,flag,parmbytes,localbytes,reglist {
  14.   local loc
  15.   loc = (localbytes+3) and (not 3)
  16.   if localbytes
  17.         sub     esp, loc
  18.   end if
  19.   irps reg, reglist \{ push reg \}
  20.   counter = 0
  21.   irps reg, reglist \{counter = counter+1 \}
  22.   parmbase@proc equ esp+counter*4+loc+4
  23.   localbase@proc equ esp
  24. }
  25.  
  26. macro omit_frame_pointer_epilogue procname,flag,parmbytes,localbytes,reglist {
  27.   local loc
  28.   loc = (localbytes+3) and (not 3)
  29.   irps reg, reglist \{ reverse pop reg \}
  30.   if localbytes
  31.         lea     esp, [esp+loc]
  32.   end if
  33.   if flag and 10000b
  34.         retn
  35.   else
  36.         retn    parmbytes
  37.   end if
  38. }
  39.  
  40. prologue@proc equ omit_frame_pointer_prologue
  41. epilogue@proc equ omit_frame_pointer_epilogue
  42.  
  43. macro movbe reg, arg {
  44.  if CPUID_MOVBE eq Y
  45.         movbe   reg, arg
  46.  else
  47.         mov     reg, arg
  48.   if reg in <eax,ebx,ecx,edx,esi,edi,ebp,esp>
  49.         bswap   reg
  50.   else if ax eq reg
  51.         xchg    al, ah
  52.   else if bx eq reg
  53.         xchg    bl, bh
  54.   else if cx eq reg
  55.         xchg    cl, ch
  56.   else if dx eq reg
  57.         xchg    dl, dh
  58.   else
  59.    err
  60.   end if
  61.  end if
  62. }
  63.  
  64. ;
  65. ; This file contains XFS related code.
  66. ; For more information on XFS check links and source below.
  67. ;
  68. ; 1. https://xfs.wiki.kernel.org/
  69. ;
  70. ; 2. XFS Algorithms & Data Structures:
  71. ;    git://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git
  72. ;    https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
  73. ;
  74. ; 3. Linux source at https://www.kernel.org/
  75. ;    git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  76. ;    /fs/xfs
  77. ;
  78.  
  79. iglobal
  80. align 4
  81. xfs._.user_functions:
  82.         dd      xfs._.free
  83.         dd      (xfs._.user_functions_end-xfs._.user_functions-4)/4
  84.         dd      xfs_Read
  85.         dd      xfs_ReadFolder
  86.         dd      0;xfs_Rewrite
  87.         dd      0;xfs_Write
  88.         dd      0;xfs_SetFileEnd
  89.         dd      xfs_GetFileInfo
  90. xfs._.user_functions_end:
  91. endg
  92.  
  93. ; test partition type (valid XFS one?)
  94. ; alloc and fill XFS (see xfs.inc) structure
  95. ; this function is called for each partition
  96. ; return 0 (not XFS or invalid) / pointer to partition structure
  97. proc xfs_create_partition uses ebx esi edi
  98.         ; check XFS signature
  99.         cmp     [ebx+xfs_sb.sb_magicnum], XFS_SB_MAGIC
  100.         jnz     .error_nofree
  101.         ; test for supported feature flags and version in sb_versionnum
  102.         movzx   eax, [ebx+xfs_sb.sb_versionnum]
  103.         xchg    al, ah
  104.         ; allow only known and supported features
  105.         ; return error otherwise
  106.         test    eax, NOT XFS_SB_VERSION_SUPPORTED
  107.         jnz     .error_nofree
  108.         ; version < 4 obsolete, not supported
  109.         ; version = 4,5 supported
  110.         ; version > 5 unknown
  111.         and     al, XFS_SB_VERSION_NUMBITS
  112.         cmp     al, 4
  113.         jb      .error_nofree
  114.         cmp     al, 5
  115.         ja      .error_nofree
  116.         ; if MOREBITS bit is set, additional feature flags are in sb_features2
  117.         test    eax, XFS_SB_VERSION_MOREBITSBIT
  118.         jz      @f
  119.         movbe   eax, [ebx+xfs_sb.sb_features2]
  120.         test    eax, NOT XFS_SB_VERSION2_SUPPORTED
  121.         jnz     .error_nofree
  122. @@:
  123.         movbe   eax, [ebx+xfs_sb.sb_features_incompat]
  124.         test    eax, NOT XFS_SB_FEAT_INCOMPAT_SUPPORTED
  125.         jnz     .error_nofree
  126.         ; all presented features are either supported or don't affect reading
  127.         movi    eax, sizeof.XFS
  128.         call    malloc
  129.         mov     edi, eax
  130.         test    eax, eax
  131.         jz      .error
  132.  
  133.         ; standard partition initialization, common for all file systems
  134.         mov     eax, dword[ebp+PARTITION.FirstSector+DQ.lo]
  135.         mov     dword[edi+XFS.FirstSector+DQ.lo], eax
  136.         mov     eax, dword[ebp+PARTITION.FirstSector+DQ.hi]
  137.         mov     dword[edi+XFS.FirstSector+DQ.hi], eax
  138.         mov     eax, dword[ebp+PARTITION.Length+DQ.lo]
  139.         mov     dword[edi+XFS.Length+DQ.lo], eax
  140.         mov     eax, dword[ebp+PARTITION.Length+DQ.hi]
  141.         mov     dword[edi+XFS.Length+DQ.hi], eax
  142.         mov     eax, [ebp+PARTITION.Disk]
  143.         mov     [edi+XFS.Disk], eax
  144.         mov     [edi+XFS.FSUserFunctions], xfs._.user_functions
  145.         ; here we initialize only one mutex (for the entire partition)
  146.         ; XFS potentially allows parallel r/w access to different AGs, keep it in mind
  147.         lea     ecx, [edi+XFS.Lock]
  148.         call    mutex_init
  149.  
  150. ;        movzx   eax, [ebx+xfs_sb.sb_sectsize]
  151. ;        xchg    al, ah
  152.         mov     eax, [eax+DISK.MediaInfo.SectorSize]
  153.         mov     [edi+XFS.sectsize], eax
  154.  
  155.         movbe   eax, [ebx+xfs_sb.sb_blocksize]
  156.         mov     [edi+XFS.blocksize], eax
  157.  
  158.         movzx   eax, [ebx+xfs_sb.sb_versionnum]
  159.         xchg    al, ah
  160.         mov     [edi+XFS.versionnum], eax
  161.         and     eax, XFS_SB_VERSION_NUMBITS
  162.         mov     [edi+XFS.version], eax
  163.  
  164.         mov     [edi+XFS.conv_time_to_kos_epoch], xfs._.conv_time_to_kos_epoch
  165.         mov     [edi+XFS.nextents_offset], xfs_inode.di_core.di_nextents
  166.  
  167.         movbe   eax, [ebx+xfs_sb.sb_features2]
  168.         mov     [edi+XFS.features2], eax
  169.         cmp     [edi+XFS.version], 5
  170.         jz      .v5
  171. .v4:
  172.         mov     [edi+XFS.inode_core_size], sizeof.xfs_dinode_core
  173.         test    eax, XFS_SB_VERSION2_FTYPE
  174.         setnz   al
  175.         movzx   eax, al
  176.         mov     [edi+XFS.ftype_size], eax
  177.         mov     [edi+XFS.dir_block_magic], XFS_DIR2_BLOCK_MAGIC
  178.         mov     [edi+XFS.dir_data_magic], XFS_DIR2_DATA_MAGIC
  179.         mov     [edi+XFS.dir_leaf1_magic], XFS_DIR2_LEAF1_MAGIC
  180.         mov     [edi+XFS.dir_leafn_magic], XFS_DIR2_LEAFN_MAGIC
  181.         mov     [edi+XFS.da_node_magic], XFS_DA_NODE_MAGIC
  182.         mov     [edi+XFS.bmap_magic], XFS_BMAP_MAGIC
  183.         mov     [edi+XFS.dirx_leaf_ents_offset], xfs_dir2_leaf.ents
  184.         mov     [edi+XFS.dirx_leaf_hdr_count_offset], xfs_dir2_leaf_hdr.count
  185.         mov     [edi+XFS.dir_block_size], sizeof.xfs_dir2_data_hdr
  186.         mov     [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt_block
  187.         mov     [edi+XFS.da_blkinfo_size], sizeof.xfs_da_blkinfo
  188.         jmp     .vcommon
  189. .v5:
  190.         mov     [edi+XFS.inode_core_size], sizeof.xfs_dinode3_core
  191.         movbe   eax, [ebx+xfs_sb.sb_features_incompat]
  192.         mov     [edi+XFS.features_incompat], eax
  193.         test    eax, XFS_SB_FEAT_INCOMPAT_FTYPE
  194.         setnz   al
  195.         movzx   eax, al
  196.         mov     [edi+XFS.ftype_size], eax
  197.         mov     [edi+XFS.dir_block_magic], XFS_DIR3_BLOCK_MAGIC
  198.         mov     [edi+XFS.dir_data_magic], XFS_DIR3_DATA_MAGIC
  199.         mov     [edi+XFS.dir_leaf1_magic], XFS_DIR3_LEAF1_MAGIC
  200.         mov     [edi+XFS.dir_leafn_magic], XFS_DIR3_LEAFN_MAGIC
  201.         mov     [edi+XFS.da_node_magic], XFS_DA3_NODE_MAGIC
  202.         mov     [edi+XFS.bmap_magic], XFS_BMAP3_MAGIC
  203.         mov     [edi+XFS.dirx_leaf_ents_offset], xfs_dir3_leaf.ents
  204.         mov     [edi+XFS.dirx_leaf_hdr_count_offset], xfs_dir3_leaf_hdr.count
  205.         mov     [edi+XFS.dir_block_size], sizeof.xfs_dir3_data_hdr
  206.         mov     [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt3_block
  207.         mov     [edi+XFS.da_blkinfo_size], sizeof.xfs_da3_blkinfo
  208.         test    [edi+XFS.features_incompat], XFS_SB_FEAT_INCOMPAT_BIGTIME
  209.         jz      @f      ; no bigtime
  210.         mov     [edi+XFS.conv_time_to_kos_epoch], xfs._.conv_bigtime_to_kos_epoch
  211. @@:
  212.         test    [edi+XFS.features_incompat], XFS_SB_FEAT_INCOMPAT_NREXT64
  213.         jz      @f      ; no bigtime
  214.         mov     [edi+XFS.nextents_offset], xfs_inode.di_core.di_big_nextents.lo_be
  215. @@:
  216. .vcommon:
  217.  
  218.         movzx   eax, [ebx+xfs_sb.sb_inodesize]
  219.         xchg    al, ah
  220.         mov     [edi+XFS.inodesize], eax
  221.  
  222.         movzx   eax, [ebx+xfs_sb.sb_inopblock]
  223.         xchg    al, ah
  224.         mov     [edi+XFS.inopblock], eax
  225.  
  226.         movzx   eax, [ebx+xfs_sb.sb_blocklog]
  227.         mov     [edi+XFS.blocklog], eax
  228.  
  229. ;        movzx   eax, [ebx+xfs_sb.sb_sectlog]
  230.         mov     eax, [edi+XFS.sectsize]
  231.         bsf     eax, eax
  232.         mov     [edi+XFS.sectlog], eax
  233.  
  234.         movzx   eax, [ebx+xfs_sb.sb_inodelog]
  235.         mov     [edi+XFS.inodelog], eax
  236.  
  237.         movzx   eax, [ebx+xfs_sb.sb_inopblog]
  238.         mov     [edi+XFS.inopblog], eax
  239.  
  240.         movzx   ecx, [ebx+xfs_sb.sb_dirblklog]
  241.         mov     [edi+XFS.dirblklog], ecx
  242.         movi    eax, 1
  243.         shl     eax, cl
  244.         mov     [edi+XFS.blkpdirblk], eax
  245.  
  246.         movbe   eax, [ebx+xfs_sb.sb_rootino.hi]
  247.         mov     [edi+XFS.rootino.lo], eax
  248.         movbe   eax, [ebx+xfs_sb.sb_rootino.lo]
  249.         mov     [edi+XFS.rootino.hi], eax
  250.  
  251.         mov     eax, [edi+XFS.blocksize]
  252.         mov     ecx, [edi+XFS.dirblklog]
  253.         shl     eax, cl
  254.         mov     [edi+XFS.dirblocksize], eax           ; blocks are for files, dirblocks are for directories
  255.  
  256.         ; sector is always smaller than block
  257.         ; so precalculate shift order to allow faster sector_num->block_num conversion
  258.         mov     ecx, [edi+XFS.blocklog]
  259.         sub     ecx, [edi+XFS.sectlog]
  260.         mov     [edi+XFS.sectpblog], ecx
  261.  
  262.         mov     eax, 1
  263.         shl     eax, cl
  264.         mov     [edi+XFS.sectpblock], eax
  265.  
  266.         movbe   eax, [ebx+xfs_sb.sb_agblocks]
  267.         mov     [edi+XFS.agblocks], eax
  268.  
  269.         movzx   ecx, [ebx+xfs_sb.sb_agblklog]
  270.         mov     [edi+XFS.agblklog], ecx
  271.  
  272.         ; get the mask for block numbers
  273.         ; block numbers are AG relative!
  274.         ; bitfield length may vary between partitions
  275.         mov     eax, 1
  276.         xor     edx, edx
  277.         shld    edx, eax, cl
  278.         shl     eax, cl
  279.         sub     eax, 1
  280.         sbb     edx, 0
  281.         mov     [edi+XFS.agblockmask.lo], eax
  282.         mov     [edi+XFS.agblockmask.hi], edx
  283.  
  284.         ; calculate magic offsets for directories
  285.         mov     ecx, [edi+XFS.blocklog]
  286.         mov     eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff        ; lo
  287.         mov     edx, XFS_DIR2_LEAF_OFFSET SHR 32                ; hi
  288.         shrd    eax, edx, cl
  289.         shr     edx, cl
  290.         mov     [edi+XFS.dir2_leaf_offset_blocks.lo], eax
  291.         mov     [edi+XFS.dir2_leaf_offset_blocks.hi], edx
  292.  
  293.         mov     ecx, [edi+XFS.blocklog]
  294.         mov     eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff        ; lo
  295.         mov     edx, XFS_DIR2_FREE_OFFSET SHR 32                ; hi
  296.         shrd    eax, edx, cl
  297.         shr     edx, cl
  298.         mov     [edi+XFS.dir2_free_offset_blocks.lo], eax
  299.         mov     [edi+XFS.dir2_free_offset_blocks.hi], edx
  300.  
  301.  
  302.         ; allocate memory for temp block, dirblock, inode, etc
  303.         mov     eax, [edi+XFS.blocksize]
  304.         call    malloc
  305.         mov     [edi+XFS.cur_block], eax
  306.         test    eax, eax
  307.         jz      .error
  308.  
  309.         mov     eax, [edi+XFS.blocksize]
  310.         call    malloc
  311.         mov     [edi+XFS.cur_block_data], eax
  312.         test    eax, eax
  313.         jz      .error
  314.  
  315.         ; we do need XFS.blocksize bytes for single inode
  316.         ; minimal file system structure is block, inodes are packed in blocks
  317.         mov     eax, [edi+XFS.blocksize]
  318.         call    malloc
  319.         mov     [edi+XFS.cur_inode], eax
  320.         test    eax, eax
  321.         jz      .error
  322.  
  323.         mov     eax, [edi+XFS.blocksize]
  324.         call    malloc
  325.         test    eax, eax
  326.         jz      .error
  327.         mov     [edi+XFS.tmp_inode], eax
  328.  
  329.         ; current sector
  330.         ; only for sector sized structures like AGF
  331.         ; inodes usually fit this size, but not always!
  332.         ; therefore never store inode here
  333.         mov     eax, [edi+XFS.sectsize]
  334.         call    malloc
  335.         mov     [edi+XFS.cur_sect], eax
  336.         test    eax, eax
  337.         jz      .error
  338.  
  339.         mov     eax, [edi+XFS.dirblocksize]
  340.         call    malloc
  341.         mov     [edi+XFS.cur_dirblock], eax
  342.         test    eax, eax
  343.         jz      .error
  344.  
  345. .quit:
  346.         ; return pointer to allocated XFS partition structure
  347.         mov     eax, edi
  348.         ret
  349. .error:
  350.         mov     eax, edi
  351.         call    xfs._.free
  352. .error_nofree:
  353.         xor     eax, eax
  354.         ret
  355. endp
  356.  
  357.  
  358. ; lock partition access mutex
  359. xfs._.lock:
  360.         lea     ecx, [ebp+XFS.Lock]
  361.         jmp     mutex_lock
  362.  
  363.  
  364. ; unlock partition access mutex
  365. xfs._.unlock:
  366.         lea     ecx, [ebp+XFS.Lock]
  367.         jmp     mutex_unlock
  368.  
  369.  
  370. ; free all the allocated memory
  371. ; called on partition destroy
  372. ; or during failed initialization from xfs_create_partition
  373. xfs._.free:
  374.         test    eax, eax
  375.         jz      .done
  376.         push    ebx
  377.         mov     ebx, eax
  378.  
  379.  
  380.         ; freeing order must correspond the order of
  381.         ; allocation in xfs_create_partition
  382.         mov     eax, [ebx+XFS.cur_block]
  383.         test    eax, eax
  384.         jz      .done
  385.         call    free
  386.  
  387.         mov     eax, [ebx+XFS.cur_block_data]
  388.         test    eax, eax
  389.         jz      .done
  390.         call    free
  391.  
  392.         mov     eax, [ebx+XFS.cur_inode]
  393.         test    eax, eax
  394.         jz      .done
  395.         call    free
  396.  
  397.         mov     eax, [ebx+XFS.tmp_inode]
  398.         test    eax, eax
  399.         jz      .done
  400.         call    free
  401.  
  402.         mov     eax, [ebx+XFS.cur_sect]
  403.         test    eax, eax
  404.         jz      .done
  405.         call    free
  406.  
  407.         mov     eax, [ebx+XFS.cur_dirblock]
  408.         test    eax, eax
  409.         jz      .done
  410.         call    free
  411.  
  412.  
  413.         mov     eax, ebx
  414.         call    free
  415.         pop     ebx
  416. .done:
  417.         ret
  418.  
  419.  
  420. ;---------------------------------------------------------------
  421. ; block number
  422. ; eax -- inode_lo
  423. ; edx -- inode_hi
  424. ; ebx -- buffer
  425. ;---------------------------------------------------------------
  426. proc xfs._.read_block
  427.         movi    ecx, 1
  428.         call    xfs._.read_blocks
  429.         ret
  430. endp
  431.  
  432.  
  433. proc xfs._.blkrel2sectabs uses esi
  434.         push    edx eax
  435.  
  436.         ; XFS block numbers are AG relative
  437.         ; they come in bitfield form of concatenated AG and block numbers
  438.         ; to get absolute block number for fs_read64_sys we should
  439.         ; 1. get AG number and multiply it by the AG size in blocks
  440.         ; 2. extract and add AG relative block number
  441.  
  442.         ; 1.
  443.         mov     ecx, [ebp+XFS.agblklog]
  444.         shrd    eax, edx, cl
  445.         shr     edx, cl
  446.         mul     [ebp+XFS.agblocks]
  447.         ; 2.
  448.         pop     ecx esi
  449.         and     ecx, [ebp+XFS.agblockmask.lo]
  450.         and     esi, [ebp+XFS.agblockmask.hi]
  451.         add     eax, ecx
  452.         adc     edx, esi
  453.  
  454.         mov     ecx, [ebp+XFS.sectpblog]
  455.         shld    edx, eax, cl
  456.         shl     eax, cl
  457.         ret
  458. endp
  459.  
  460.  
  461. ;---------------------------------------------------------------
  462. ; start block number
  463. ; edx:eax -- block
  464. ; ebx -- buffer
  465. ; ecx -- count
  466. ;---------------------------------------------------------------
  467. proc xfs._.read_blocks
  468.         push    ecx
  469.         call    xfs._.blkrel2sectabs
  470.         pop     ecx
  471.         imul    ecx, [ebp+XFS.sectpblock]
  472.         call    fs_read64_sys
  473.         test    eax, eax
  474.         ret
  475. endp
  476.  
  477.  
  478. proc xfs._.read_dirblock uses ebx, _startblock:qword, _buffer
  479.         mov     eax, dword[_startblock+DQ.lo]
  480.         mov     edx, dword[_startblock+DQ.hi]
  481.         mov     ebx, [_buffer]
  482.         mov     ecx, [ebp+XFS.blkpdirblk]
  483.         call    xfs._.read_blocks
  484.         ret
  485. endp
  486.  
  487.  
  488. ;---------------------------------------------------------------
  489. ; test eax, eax
  490. ;---------------------------------------------------------------
  491. proc xfs_read_inode uses ebx, _inode_lo, _inode_hi, _buffer
  492.         mov     eax, [_inode_lo]
  493.         mov     edx, [_inode_hi]
  494.         mov     ebx, [_buffer]
  495.         ; inodes are packed into blocks
  496.         ; 1. calculate block number
  497.         ; 2. read the block
  498.         ; 3. add inode offset to block base address
  499.         ; 1.
  500.         mov     ecx, [ebp+XFS.inopblog]
  501.         shrd    eax, edx, cl
  502.         shr     edx, cl
  503.         ; 2.
  504.         call    xfs._.read_block
  505.         jnz     .error
  506.         ; inode numbers should be first extracted from bitfields by mask
  507.  
  508.         mov     eax, [_inode_lo]
  509.         mov     edx, 1
  510.         mov     ecx, [ebp+XFS.inopblog]
  511.         shl     edx, cl
  512.         dec     edx             ; get inode number mask
  513.         and     eax, edx        ; apply mask
  514.         mov     ecx, [ebp+XFS.inodelog]
  515.         shl     eax, cl
  516.         add     ebx, eax
  517.         xor     eax, eax
  518.  
  519.         cmp     [ebx+xfs_inode.di_core.di_magic], XFS_DINODE_MAGIC
  520.         jz      .quit
  521.         movi    eax, ERROR_FS_FAIL
  522. .quit:
  523.         mov     edx, ebx
  524. .error:
  525.         ret
  526. endp
  527.  
  528.  
  529. ; skip ecx first entries
  530. proc xfs._.dir_sf_skip _count
  531.         mov     ecx, [_count]
  532. .next:
  533.         dec     ecx
  534.         js      .quit
  535.         dec     [ebp+XFS.entries_left_in_dir]
  536.         js      .quit
  537. .self:
  538.         bts     [ebp+XFS.dir_sf_self_done], 0
  539.         jc      .parent
  540.         jmp     .next
  541. .parent:
  542.         bts     [ebp+XFS.dir_sf_parent_done], 0
  543.         jc      .common
  544.         jmp     .next
  545. .common:
  546.         movzx   eax, [esi+xfs_dir2_sf_entry.namelen]
  547.         add     esi, xfs_dir2_sf_entry.name
  548.         add     esi, eax
  549.         add     esi, [ebp+XFS.ftype_size]
  550.         add     esi, [ebp+XFS.shortform_inodelen]
  551.         jmp     .next
  552. .quit:
  553.         ret
  554. endp
  555.  
  556.  
  557. proc xfs._.dir_sf_read uses edi, _count
  558. locals
  559.         _dst dd ?
  560. endl
  561. .next:
  562.         dec     [_count]
  563.         js      .quit
  564.         dec     [ebp+XFS.entries_left_in_dir]
  565.         js      .quit
  566.         mov     [_dst], edx
  567. .self:
  568.         bts     [ebp+XFS.dir_sf_self_done], 0
  569.         jc      .parent
  570.         lea     edi, [edx+bdfe.name]
  571.         mov     dword[edi], '.'
  572.         stdcall xfs_get_inode_info, [ebp+XFS.cur_inode], edx
  573.         jmp     .common
  574. .parent:
  575.         bts     [ebp+XFS.dir_sf_parent_done], 0
  576.         jc      .not_special
  577.         lea     edi, [edx+bdfe.name]         ; get file name offset
  578.         mov     dword[edi], '..'        ; terminator included
  579.         mov     edi, edx
  580.         lea     edx, [ebx+xfs_dir2_sf.hdr.parent]
  581.         call    xfs._.get_inode_number_sf
  582.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
  583.         test    eax, eax
  584.         jnz     .error
  585.         stdcall xfs_get_inode_info, edx, edi
  586.         jmp     .common
  587. .not_special:
  588.         movzx   ecx, [esi+xfs_dir2_sf_entry.namelen]
  589.         add     esi, xfs_dir2_sf_entry.name
  590.         lea     edi, [edx+bdfe.name]
  591.         stdcall xfs._.copy_filename
  592.         add     esi, [ebp+XFS.ftype_size]
  593.         mov     edi, edx
  594.         mov     edx, esi
  595.         call    xfs._.get_inode_number_sf
  596.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
  597.         test    eax, eax
  598.         jnz     .error
  599.         stdcall xfs_get_inode_info, edx, edi
  600.         add     esi, [ebp+XFS.shortform_inodelen]
  601. .common:
  602.         mov     edx, [_dst]
  603.         mov     eax, [ebp+XFS.bdfe_nameenc]
  604.         mov     [edx+bdfe.nameenc], eax
  605.         add     edx, [ebp+XFS.bdfe_len]
  606.         inc     [ebp+XFS.entries_read]
  607.         jmp     .next
  608. .quit:
  609.         xor     eax, eax
  610. .error:
  611.         ret
  612. endp
  613.  
  614.  
  615. proc xfs._.readdir_sf uses esi, _src, _dst
  616.         mov     ebx, [_src]
  617.         mov     edx, [_dst]
  618.         mov     [ebp+XFS.dir_sf_self_done], 0
  619.         mov     [ebp+XFS.dir_sf_parent_done], 0
  620.         mov     [ebp+XFS.entries_read], 0
  621.         movzx   eax, [ebx+xfs_dir2_sf.hdr.count]
  622.         ; '..' and '.' are implicit
  623.         add     eax, 2
  624.         mov     [ebp+XFS.entries_left_in_dir], eax
  625.         mov     [edx+bdfe_hdr.total_cnt], eax
  626.         ; inode numbers are often saved as 4 bytes (iff they fit)
  627.         ; compute the length of inode numbers
  628.         ; 8 iff i8count != 0, 4 otherwise
  629.         cmp     [ebx+xfs_dir2_sf.hdr.i8count], 0
  630.         setnz   al
  631.         lea     eax, [eax*4+4]
  632.         mov     [ebp+XFS.shortform_inodelen], eax
  633.         add     edx, sizeof.bdfe_hdr
  634.         lea     esi, [ebx+xfs_dir2_sf.hdr.parent+eax]
  635.         stdcall xfs._.dir_sf_skip, [ebp+XFS.entries_to_skip]
  636.         stdcall xfs._.dir_sf_read, [ebp+XFS.requested_cnt]
  637.         ret
  638. endp
  639.  
  640.  
  641. proc xfs._.readdir_block _literal_area, _out_buf
  642.         mov     ebx, [_literal_area]
  643.         mov     [ebp+XFS.entries_read], 0
  644.         mov     eax, ebx
  645.         mov     ebx, [ebp+XFS.cur_dirblock]
  646.         stdcall xfs._.extent_unpack, eax
  647.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
  648.         mov     edx, [_out_buf]
  649.         jnz     .error
  650.         mov     eax, [ebp+XFS.dir_block_magic]
  651.         cmp     [ebx+xfs_dir2_block.hdr.magic], eax
  652.         movi    eax, ERROR_FS_FAIL
  653.         jnz     .error
  654.         mov     eax, [ebp+XFS.dirblocksize]
  655.         movbe   ecx, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.stale]
  656.         movbe   eax, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
  657.         sub     eax, ecx        ; actual number of entries = count - stale
  658.         mov     [ebp+XFS.entries_left_in_dir], eax
  659.         mov     [edx+bdfe_hdr.total_cnt], eax
  660.  
  661.         add     ebx, [ebp+XFS.dir_block_size]
  662.         add     edx, sizeof.bdfe_hdr
  663.         mov     [_out_buf], edx
  664.         lea     edi, [_out_buf]
  665. .next:
  666.         movi    eax, ERROR_SUCCESS
  667.         cmp     [ebp+XFS.requested_cnt], 0
  668.         jz      .quit
  669.         cmp     [ebp+XFS.entries_left_in_dir], 0
  670.         jz      .quit
  671.         stdcall xfs._.dir_entry_skip_read, edi
  672.         jz      .next
  673. .error:
  674. .quit:
  675.         ret
  676. endp
  677.  
  678.  
  679. proc xfs._.readdir_leaf_node uses esi, _inode_data, _out_buf
  680.         mov     ebx, [_inode_data]
  681.         mov     edx, [_out_buf]
  682.         mov     [ebp+XFS.cur_inode_save], ebx
  683.         mov     [ebp+XFS.entries_read], 0
  684.         mov     eax, ebx
  685.         add     eax, [ebp+XFS.inode_core_size]
  686.         mov     edx, [ebp+XFS.nextents_offset]
  687.         movbe   edx, [ebx+edx]
  688.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  689.         mov     [ebp+XFS.offset_begin.lo], ecx
  690.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
  691.         mov     [ebp+XFS.offset_begin.hi], ecx
  692.         mov     ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
  693.         mov     [ebp+XFS.offset_end.lo], ecx
  694.         mov     ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
  695.         mov     [ebp+XFS.offset_end.hi], ecx
  696.         stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0
  697.         jnz     .error
  698.         mov     eax, [ebp+XFS.entries_read]
  699.         mov     edx, [_out_buf]
  700.         mov     [edx+bdfe_hdr.total_cnt], eax
  701.         mov     [ebp+XFS.entries_left_in_dir], eax
  702.         add     [_out_buf], sizeof.bdfe_hdr
  703.         mov     [ebp+XFS.entries_read], 0
  704.         mov     edx, [ebp+XFS.nextents_offset]
  705.         movbe   edx, [ebx+edx]
  706.         mov     eax, ebx
  707.         add     eax, [ebp+XFS.inode_core_size]
  708.         lea     ecx, [_out_buf]
  709.         push    ecx
  710.         mov     [ebp+XFS.offset_begin.lo], 0
  711.         mov     [ebp+XFS.offset_begin.hi], 0
  712.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  713.         mov     [ebp+XFS.offset_end.lo], ecx
  714.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
  715.         mov     [ebp+XFS.offset_end.hi], ecx
  716.         pop     ecx
  717.         stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx
  718. ;        jnz     .error
  719. .error:
  720. .quit:
  721.         ret
  722. endp
  723.  
  724.  
  725. proc xfs._.dir_entry_skip_read uses esi edi, _arg
  726.         cmp     [ebx+xfs_dir2_data_union.unused.freetag], XFS_NULL
  727.         jnz     @f
  728.         movzx   eax, [ebx+xfs_dir2_data_union.unused.length]
  729.         xchg    al, ah
  730.         add     ebx, eax
  731.         jmp     .quit
  732. @@:
  733.         cmp     [ebp+XFS.entries_to_skip], 0
  734.         jz      .read
  735. .skip:
  736.         dec     [ebp+XFS.entries_to_skip]
  737.         movzx   ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
  738.         lea     ebx, [ebx+xfs_dir2_data_union.xentry.name+ecx+2]
  739.         add     ebx, [ebp+XFS.ftype_size]
  740.         jmp     .common
  741. .read:
  742.         dec     [ebp+XFS.requested_cnt]
  743.         inc     [ebp+XFS.entries_read]
  744.         mov     edi, [_arg]
  745.         mov     edi, [edi]
  746.         movbe   edx, [ebx+xfs_dir2_data_union.xentry.inumber.lo]
  747.         movbe   eax, [ebx+xfs_dir2_data_union.xentry.inumber.hi]
  748.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
  749.         stdcall xfs_get_inode_info, edx, edi
  750.         jnz     .error
  751.         mov     edx, [_arg]
  752.         mov     edx, [edx]
  753.         mov     ecx, [ebp+XFS.bdfe_nameenc]
  754.         mov     [edx+bdfe.nameenc], ecx
  755.         lea     edi, [edx+bdfe.name]
  756.         movzx   ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
  757.         lea     esi, [ebx+xfs_dir2_data_union.xentry.name]
  758.         stdcall xfs._.copy_filename
  759.         lea     ebx, [esi+2]  ; skip 'tag'
  760.         add     ebx, [ebp+XFS.ftype_size]
  761.         mov     eax, [_arg]
  762.         mov     edx, [eax]
  763.         add     edx, [ebp+XFS.bdfe_len]
  764.         mov     [eax], edx
  765. .common:
  766.         sub     ebx, [ebp+XFS.cur_dirblock]
  767.         add     ebx, 7          ; xfs_dir2_data_entries are aligned to 8 bytes
  768.         and     ebx, not 7
  769.         add     ebx, [ebp+XFS.cur_dirblock]
  770.         dec     [ebp+XFS.entries_left_in_dir]
  771. .quit:
  772.         movi    eax, ERROR_SUCCESS
  773.         cmp     esp, esp
  774. .error:
  775.         ret
  776. endp
  777.  
  778.  
  779. proc xfs._.dir_btree_skip_read uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
  780.         mov     ebx, [_cur_dirblock]
  781.         mov     eax, [ebp+XFS.dir_data_magic]
  782.         cmp     [ebx+xfs_dir2_block.hdr.magic], eax
  783.         movi    eax, ERROR_FS_FAIL
  784.         jnz     .error
  785.         mov     eax, ebx
  786.         add     eax, [ebp+XFS.dirblocksize]
  787.         mov     [ebp+XFS.max_dirblockaddr], eax
  788.         add     ebx, [ebp+XFS.dir_block_size]
  789. .next:
  790.         movi    eax, ERROR_SUCCESS
  791.         cmp     [ebp+XFS.requested_cnt], 0
  792.         jz      .quit
  793.         cmp     [ebp+XFS.entries_left_in_dir], 0
  794.         jz      .quit
  795.         cmp     ebx, [ebp+XFS.max_dirblockaddr]
  796.         jz      .quit
  797.         stdcall xfs._.dir_entry_skip_read, [_arg]
  798.         jz      .next
  799. .error:
  800. .quit:
  801.         ret
  802. endp
  803.  
  804.  
  805. proc xfs._.readdir_btree uses esi, _inode_data, _out_buf
  806.         mov     [ebp+XFS.cur_inode_save], ebx
  807.         mov     [ebp+XFS.entries_read], 0
  808.         mov     eax, [ebp+XFS.inodesize]
  809.         sub     eax, [ebp+XFS.inode_core_size]
  810.         movzx   ecx, [ebx+xfs_inode.di_core.di_forkoff]
  811.         jecxz   @f
  812.         shl     ecx, 3
  813.         mov     eax, ecx
  814. @@:
  815.         mov     edx, ebx
  816.         add     edx, [ebp+XFS.inode_core_size]
  817.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  818.         mov     [ebp+XFS.offset_begin.lo], ecx
  819.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
  820.         mov     [ebp+XFS.offset_begin.hi], ecx
  821.         mov     ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
  822.         mov     [ebp+XFS.offset_end.lo], ecx
  823.         mov     ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
  824.         mov     [ebp+XFS.offset_end.hi], ecx
  825.         stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0, 1
  826.         mov     eax, [ebp+XFS.entries_read]
  827.         mov     edx, [_out_buf]
  828.         mov     [edx+bdfe_hdr.total_cnt], eax
  829.         mov     [ebp+XFS.entries_left_in_dir], eax
  830.         mov     [ebp+XFS.entries_read], 0
  831.         add     [_out_buf], sizeof.bdfe_hdr
  832.         mov     eax, [ebp+XFS.inodesize]
  833.         sub     eax, [ebp+XFS.inode_core_size]
  834.         movzx   ecx, [ebx+xfs_inode.di_core.di_forkoff]
  835.         jecxz   @f
  836.         shl     ecx, 3
  837.         mov     eax, ecx
  838. @@:
  839.         mov     edx, ebx
  840.         add     edx, [ebp+XFS.inode_core_size]
  841.         mov     [ebp+XFS.offset_begin.lo], 0
  842.         mov     [ebp+XFS.offset_begin.hi], 0
  843.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  844.         mov     [ebp+XFS.offset_end.lo], ecx
  845.         mov     ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
  846.         mov     [ebp+XFS.offset_end.hi], ecx
  847.         mov     ecx, [_out_buf]
  848.         push    ecx
  849.         mov     ecx, esp
  850.         stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx, 1
  851.         pop     ecx
  852. .error:
  853. .quit:
  854.         ret
  855. endp
  856.  
  857.  
  858. proc xfs._.copy_filename uses eax
  859.         mov     eax, [ebp+XFS.bdfe_nameenc]
  860.         cmp     eax, 3
  861.         jz      .utf8
  862.         cmp     eax, 2
  863.         jz      .utf16
  864. .cp866:
  865.         call    unicode.utf8.decode
  866.         call    unicode.cp866.encode
  867.         stosb
  868.         test    ecx, ecx
  869.         jnz     .cp866
  870.         mov     byte[edi], 0
  871.         jmp     .done
  872. .utf16:
  873.         call    unicode.utf8.decode
  874.         call    unicode.utf16.encode
  875.         stosw
  876.         shr     eax, 16
  877.         jz      @f
  878.         stosw
  879. @@:
  880.         test    ecx, ecx
  881.         jnz     .utf16
  882.         mov     word[edi], 0
  883.         jmp     .done
  884. .utf8:
  885.         rep movsb
  886.         mov     byte[edi], 0
  887. .done:
  888.         ret
  889. endp
  890.  
  891. ;----------------------------------------------------------------
  892. ; src              ; inode
  893. ; dst              ; bdfe
  894. ; start_number     ; from 0
  895. ;----------------------------------------------------------------
  896. proc xfs._.readdir uses ebx esi edi, _start_number, _entries_to_read, _dst, _src, _encoding
  897.         mov     ecx, [_start_number]
  898.         mov     [ebp+XFS.entries_to_skip], ecx
  899.         mov     eax, [_entries_to_read]
  900.         mov     [ebp+XFS.requested_cnt], eax
  901.         mov     eax, [_encoding]
  902.         mov     [ebp+XFS.bdfe_nameenc], eax
  903.         mov     ecx, 304
  904.         cmp     eax, 1  ; CP866
  905.         jbe     @f
  906.         mov     ecx, 560
  907. @@:
  908.         mov     [ebp+XFS.bdfe_len], ecx
  909.         mov     edx, [_dst]
  910.         mov     [ebp+XFS.bdfe_buf], edx
  911.         mov     ebx, [_src]
  912.         mov     [ebp+XFS.cur_inode_save], ebx
  913.  
  914.         mov     [edx+bdfe_hdr.version], 1
  915.         mov     [edx+bdfe_hdr.zeroed+0x00], 0
  916.         mov     [edx+bdfe_hdr.zeroed+0x04], 0
  917.         mov     [edx+bdfe_hdr.zeroed+0x08], 0
  918.         mov     [edx+bdfe_hdr.zeroed+0x0c], 0
  919.         mov     [edx+bdfe_hdr.zeroed+0x10], 0
  920.  
  921.         movzx   eax, [ebx+xfs_inode.di_core.di_format]
  922.         ; switch directory ondisk format and jump to corresponding label
  923.         cmp     eax, XFS_DINODE_FMT_LOCAL
  924.         jnz     @f
  925.         add     ebx, [ebp+XFS.inode_core_size]
  926.         stdcall xfs._.readdir_sf, ebx, [_dst]
  927.         test    eax, eax
  928.         jnz     .error
  929.         jmp     .quit
  930. @@:
  931.         cmp     eax, XFS_DINODE_FMT_BTREE
  932.         jnz     @f
  933.         stdcall xfs._.readdir_btree, ebx, [_dst]
  934.         jmp     .quit
  935. @@:
  936.         cmp     eax, XFS_DINODE_FMT_EXTENTS
  937.         movi    eax, ERROR_FS_FAIL
  938.         jnz     .error
  939.         call    xfs._.get_last_dirblock
  940.         test    eax, eax
  941.         jnz     @f
  942.         add     ebx, [ebp+XFS.inode_core_size]
  943.         stdcall xfs._.readdir_block, ebx, [_dst]
  944.         jmp     .quit
  945. @@:
  946.         stdcall xfs._.readdir_leaf_node, ebx, [_dst]
  947.         jmp     .quit
  948. .quit:
  949.         mov     edx, [_dst]
  950.         mov     ebx, [ebp+XFS.entries_read]
  951.         mov     [edx+bdfe_hdr.read_cnt], ebx
  952.         xor     eax, eax
  953. .error:
  954.         ret
  955. endp
  956.  
  957.  
  958. ; returns edx:eax inode or 0
  959. proc xfs._.lookup_sf _name, _len
  960.         add     ebx, [ebp+XFS.inode_core_size]
  961.         mov     esi, [_name]
  962.         mov     ecx, [_len]
  963.         cmp     ecx, 2
  964.         ja      .common
  965.         jz      .check_parent
  966. .check_self:
  967.         cmp     byte[esi], '.'
  968.         jnz     .common
  969.         mov     eax, [ebp+XFS.inode_self.lo]
  970.         mov     edx, [ebp+XFS.inode_self.hi]
  971.         jmp     .quit
  972. .check_parent:
  973.         cmp     word[esi], '..'
  974.         jnz     .common
  975.         lea     edx, [ebx+xfs_dir2_sf.hdr.parent]
  976.         call    xfs._.get_inode_number_sf
  977.         jmp     .quit
  978. .common:
  979.         movzx   edx, [ebx+xfs_dir2_sf.hdr.count]
  980.         movi    eax, 0
  981.         cmp     [ebx+xfs_dir2_sf.hdr.i8count], 0
  982.         setnz   al
  983.         lea     eax, [eax*4+4]
  984.         lea     edi, [ebx+xfs_dir2_sf.hdr.parent+eax]
  985. .next_name:
  986.         dec     edx
  987.         jns     @f
  988.         movi    eax, ERROR_FILE_NOT_FOUND
  989.         jmp     .error
  990. @@:
  991.         movzx   ecx, [edi+xfs_dir2_sf_entry.namelen]
  992.         add     edi, xfs_dir2_sf_entry.name
  993.         mov     esi, [_name]
  994.         cmp     ecx, [_len]
  995.         jnz     @f
  996.         repz cmpsb
  997.         jz      .found
  998. @@:
  999.         add     edi, [ebp+XFS.ftype_size]
  1000.         add     edi, ecx
  1001.         add     edi, eax
  1002.         jmp     .next_name
  1003. .found:
  1004.         add     edi, [ebp+XFS.ftype_size]
  1005.         mov     edx, edi
  1006.         call    xfs._.get_inode_number_sf
  1007. .quit:
  1008.         cmp     esp, esp
  1009. .error:
  1010.         ret
  1011. endp
  1012.  
  1013.  
  1014. proc xfs._.lookup_block uses esi, _name, _len
  1015.         add     ebx, [ebp+XFS.inode_core_size]
  1016.         mov     eax, ebx
  1017.         mov     ebx, [ebp+XFS.cur_dirblock]
  1018.         stdcall xfs._.extent_unpack, eax
  1019.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], \
  1020.                 [ebp+XFS.extent.br_startblock.hi], ebx
  1021.         jnz     .error
  1022.         mov     eax, [ebp+XFS.dir_block_magic]
  1023.         cmp     [ebx+xfs_dir2_block.hdr.magic], eax
  1024.         movi    eax, ERROR_FS_FAIL
  1025.         jnz     .error
  1026.         stdcall xfs_hashname, [_name+4], [_len]
  1027.         add     ebx, [ebp+XFS.dirblocksize]
  1028.         movbe   ecx, [ebx-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
  1029.         lea     edx, [ecx*sizeof.xfs_dir2_leaf_entry+sizeof.xfs_dir2_block_tail]
  1030.         sub     ebx, edx
  1031.         stdcall xfs._.get_addr_by_hash, ebx, ecx
  1032.         jnz     .error
  1033.         mov     ebx, [ebp+XFS.cur_dirblock]
  1034.         movbe   edx, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.lo]
  1035.         movbe   eax, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.hi]
  1036. .quit:
  1037. .error:
  1038.         ret
  1039. endp
  1040.  
  1041.  
  1042. proc xfs._.get_inode_by_addr uses ebx esi edi, _inode_buf
  1043.         xor     edx, edx
  1044.         shld    edx, eax, XFS_DIR2_DATA_ALIGN_LOG
  1045.         shl     eax, XFS_DIR2_DATA_ALIGN_LOG
  1046.         mov     esi, [ebp+XFS.dirblocksize]
  1047.         dec     esi
  1048.         and     esi, eax
  1049.         mov     ecx, [ebp+XFS.blocklog]
  1050.         add     ecx, [ebp+XFS.dirblklog]
  1051.         shrd    eax, edx, cl
  1052.         shr     edx, cl
  1053.         mov     ecx, [ebp+XFS.dirblklog]
  1054.         shld    edx, eax, cl
  1055.         shl     eax, cl
  1056.         mov     ebx, [_inode_buf]
  1057.         cmp     [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  1058.         jz      .extents
  1059.         cmp     [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
  1060.         jz      .btree
  1061.         jmp     .error
  1062. .extents:
  1063.         mov     ecx, [ebp+XFS.nextents_offset]
  1064.         movbe   ecx, [ebx+ecx]
  1065.         add     ebx, [ebp+XFS.inode_core_size]
  1066.         mov     [ebp+XFS.offset_begin.lo], eax
  1067.         mov     [ebp+XFS.offset_begin.hi], edx
  1068.         stdcall xfs._.extent_list.seek, ecx
  1069.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
  1070.         jnz     .error
  1071.         jmp     .common
  1072. .btree:
  1073.         movzx   ecx, [ebx+xfs_inode.di_core.di_forkoff]
  1074.         shl     ecx, 3
  1075.         test    ecx, ecx
  1076.         jnz     @f
  1077.         mov     ecx, [ebp+XFS.inodesize]
  1078.         sub     ecx, [ebp+XFS.inode_core_size]
  1079. @@:
  1080.         add     ebx, [ebp+XFS.inode_core_size]
  1081.         stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
  1082. .common:
  1083.         mov     ebx, [ebp+XFS.cur_dirblock]
  1084.         mov     eax, [ebp+XFS.dir_data_magic]
  1085.         cmp     [ebx+xfs_dir2_block.hdr.magic], eax
  1086.         movi    eax, ERROR_FS_FAIL
  1087.         jnz     .error
  1088.         movbe   edx, [ebx+esi+xfs_dir2_data_entry.inumber.lo]
  1089.         movbe   eax, [ebx+esi+xfs_dir2_data_entry.inumber.hi]
  1090. .error:
  1091. .quit:
  1092.         ret
  1093. endp
  1094.  
  1095.  
  1096. proc xfs._.lookup_leaf uses ebx esi edi, _name, _len
  1097.         mov     ecx, [ebp+XFS.nextents_offset]
  1098.         movbe   ecx, [ebx+ecx]
  1099.         add     ebx, [ebp+XFS.inode_core_size]
  1100.         mov     eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  1101.         mov     [ebp+XFS.offset_begin.lo], ecx
  1102.         mov     eax, [ebp+XFS.dir2_leaf_offset_blocks.hi]
  1103.         mov     [ebp+XFS.offset_begin.hi], ecx
  1104.         stdcall xfs._.extent_list.seek, ecx
  1105.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], \
  1106.                 [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
  1107.         jnz     .error
  1108.         mov     ebx, [ebp+XFS.cur_dirblock]
  1109.         movzx   eax, [ebp+XFS.dir_leaf1_magic]
  1110.         cmp     [ebx+xfs_dir2_leaf.hdr.info.magic], ax
  1111.         movi    eax, ERROR_FS_FAIL
  1112.         jnz     .error
  1113.         stdcall xfs_hashname, [_name+4], [_len]
  1114.         cmp     [ebp+XFS.version], 5
  1115.         jz      .v5
  1116. .v4:
  1117.         movzx   ecx, [ebx+xfs_dir2_leaf.hdr.count]
  1118.         xchg    cl, ch
  1119.         add     ebx, xfs_dir2_leaf.ents
  1120.         jmp     .vcommon
  1121. .v5:
  1122.         movzx   ecx, [ebx+xfs_dir3_leaf.hdr.count]
  1123.         xchg    cl, ch
  1124.         add     ebx, xfs_dir3_leaf.ents
  1125. .vcommon:
  1126.         stdcall xfs._.get_addr_by_hash, ebx, ecx
  1127.         jnz     .error
  1128.         stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
  1129. .quit:
  1130. .error:
  1131.         ret
  1132. endp
  1133.  
  1134.  
  1135. proc xfs._.lookup_node uses ebx esi edi, _name, _len
  1136. locals
  1137.         .hash dd ?
  1138. endl
  1139.         mov     [ebp+XFS.cur_inode_save], ebx
  1140.         stdcall xfs_hashname, [_name+4], [_len]
  1141.         mov     [.hash], eax
  1142.         mov     edx, [ebp+XFS.nextents_offset]
  1143.         movbe   edx, [ebx+edx]
  1144.         mov     esi, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  1145. .begin:
  1146.         mov     ebx, [ebp+XFS.cur_inode_save]
  1147.         mov     eax, ebx
  1148.         add     eax, [ebp+XFS.inode_core_size]
  1149.         mov     edx, [ebp+XFS.nextents_offset]
  1150.         movbe   edx, [ebx+edx]
  1151.         mov     ebx, eax
  1152.         mov     [ebp+XFS.offset_begin.lo], esi
  1153.         mov     [ebp+XFS.offset_begin.hi], 0
  1154.         stdcall xfs._.extent_list.seek, edx
  1155.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
  1156.         jnz     .error
  1157.         mov     ebx, [ebp+XFS.cur_dirblock]
  1158.         movzx   eax, [ebp+XFS.da_node_magic]
  1159.         cmp     [ebx+xfs_da_intnode.hdr.info.magic], ax
  1160.         jz      .node
  1161.         movzx   eax, [ebp+XFS.dir_leafn_magic]
  1162.         cmp     [ebx+xfs_dir2_leaf.hdr.info.magic], ax
  1163.         jz      .leaf
  1164.         movi    eax, ERROR_FS_FAIL
  1165.         jmp     .error
  1166. .node:
  1167.         cmp     [ebp+XFS.version], 5
  1168.         jz      .node.v5
  1169. .node.v4:
  1170.         lea     eax, [ebx+sizeof.xfs_da_intnode]
  1171.         movzx   edx, [ebx+xfs_da_intnode.hdr.count]
  1172.         jmp     .node.vcommon
  1173. .node.v5:
  1174.         lea     eax, [ebx+sizeof.xfs_da3_intnode]
  1175.         movzx   edx, [ebx+xfs_da3_intnode.hdr.count]
  1176. .node.vcommon:
  1177.         xchg    dl, dh
  1178.         stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
  1179.         jnz     .error
  1180.         mov     esi, eax
  1181.         jmp     .begin
  1182. .leaf:
  1183.         cmp     [ebp+XFS.version], 5
  1184.         jz      .leaf.v5
  1185. .leaf.v4:
  1186.         movzx   ecx, [ebx+xfs_dir2_leaf.hdr.count]
  1187.         xchg    cl, ch
  1188.         add     ebx, xfs_dir2_leaf.ents
  1189.         jmp     .leaf.vcommon
  1190. .leaf.v5:
  1191.         movzx   ecx, [ebx+xfs_dir3_leaf.hdr.count]
  1192.         xchg    cl, ch
  1193.         add     ebx, xfs_dir3_leaf.ents
  1194. .leaf.vcommon:
  1195.         mov     eax, [.hash]
  1196.         stdcall xfs._.get_addr_by_hash, ebx, ecx
  1197.         jnz     .error
  1198.         stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
  1199. .quit:
  1200.         cmp     esp, esp
  1201.         ret
  1202. .error:
  1203.         test    esp, esp
  1204.         ret
  1205. endp
  1206.  
  1207.  
  1208. proc xfs._.lookup_btree uses ebx esi edi, _name, _len
  1209. locals
  1210.         .hash dd ?
  1211. endl
  1212.         mov     [ebp+XFS.cur_inode_save], ebx
  1213.         stdcall xfs_hashname, [_name+4], [_len]
  1214.         mov     [.hash], eax
  1215.         mov     edx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
  1216.         mov     eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
  1217.         jmp     .next_level.first
  1218. .next_level:
  1219.         lea     eax, [ebx+sizeof.xfs_da_intnode]
  1220.         movzx   edx, [ebx+xfs_da_intnode.hdr.count]
  1221.         xchg    dl, dh
  1222.         stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
  1223.         jnz     .error
  1224.         xor     edx, edx
  1225. .next_level.first:
  1226.         mov     ebx, [ebp+XFS.cur_inode_save]
  1227.         movzx   ecx, [ebx+xfs_inode.di_core.di_forkoff]
  1228.         shl     ecx, 3
  1229.         test    ecx, ecx
  1230.         jnz     @f
  1231.         mov     ecx, [ebp+XFS.inodesize]
  1232.         sub     ecx, [ebp+XFS.inode_core_size]
  1233. @@:
  1234.         add     ebx, [ebp+XFS.inode_core_size]
  1235.         stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
  1236.         mov     ebx, [ebp+XFS.cur_dirblock]
  1237.         movzx   eax, [ebp+XFS.da_node_magic]
  1238.         cmp     [ebx+xfs_da_blkinfo.magic], ax
  1239.         jz      .next_level
  1240.         movzx   eax, [ebp+XFS.dir_leafn_magic]
  1241.         cmp     [ebx+xfs_da_blkinfo.magic], ax
  1242.         jz      .leafn
  1243.         movzx   eax, [ebp+XFS.dir_leaf1_magic]
  1244.         cmp     [ebx+xfs_da_blkinfo.magic], ax
  1245.         jnz     .error
  1246.         mov     eax, [.hash]
  1247.         mov     ecx, [ebp+XFS.dirx_leaf_hdr_count_offset]
  1248.         movzx   ecx, word[ebx+ecx]
  1249.         xchg    cl, ch
  1250.         add     ebx, [ebp+XFS.dirx_leaf_ents_offset]
  1251.         stdcall xfs._.get_addr_by_hash, ebx, ecx
  1252.         jnz     .error
  1253.         mov     ebx, [ebp+XFS.cur_dirblock]
  1254.         jmp     .got_addr
  1255. .leafn:
  1256.         mov     ecx, [ebp+XFS.dirx_leaf_hdr_count_offset]
  1257.         movzx   ecx, word[ebx+ecx]
  1258.         xchg    cl, ch
  1259.         add     ebx, [ebp+XFS.dirx_leaf_ents_offset]
  1260.         mov     eax, [.hash]
  1261.         stdcall xfs._.get_addr_by_hash, ebx, ecx
  1262.         jnz     .error
  1263.         mov     ebx, [ebp+XFS.cur_block]
  1264. .got_addr:
  1265.         stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
  1266. .quit:
  1267.         cmp     esp, esp
  1268.         ret
  1269. .error:
  1270.         test    esp, esp
  1271.         ret
  1272. endp
  1273.  
  1274.  
  1275. ; search for the _name in _inode dir
  1276. ; called for each /path/component/to/my/file
  1277. ; out:
  1278. ; ZF/zf   = ok/fail
  1279. ; edx:eax = inode/garbage:error
  1280. proc xfs._.get_inode_short uses esi, _inode:qword, _len, _name
  1281.         mov     esi, [_name]
  1282.         mov     eax, dword[_inode+DQ.lo]
  1283.         mov     edx, dword[_inode+DQ.hi]
  1284.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
  1285.         test    eax, eax
  1286.         movi    eax, ERROR_FS_FAIL
  1287.         jnz     .error
  1288.         ; switch directory ondisk format
  1289.         mov     ebx, edx
  1290.         mov     [ebp+XFS.cur_inode_save], ebx
  1291.         movzx   eax, [ebx+xfs_inode.di_core.di_format]
  1292.         cmp     eax, XFS_DINODE_FMT_LOCAL
  1293.         mov     edi, xfs._.lookup_sf
  1294.         jz      .lookup
  1295.         cmp     eax, XFS_DINODE_FMT_BTREE
  1296.         mov     edi, xfs._.lookup_btree
  1297.         jz      .lookup
  1298.         cmp     eax, XFS_DINODE_FMT_EXTENTS
  1299.         jnz     .error
  1300.         call    xfs._.get_last_dirblock
  1301.         test    eax, eax
  1302.         mov     edi, xfs._.lookup_block
  1303.         jz      .lookup
  1304.         cmp     edx, [ebp+XFS.dir2_free_offset_blocks.hi]
  1305.         mov     edi, xfs._.lookup_node
  1306.         ja      .lookup
  1307.         cmp     eax, [ebp+XFS.dir2_free_offset_blocks.lo]
  1308.         jae     .lookup
  1309.         mov     edi, xfs._.lookup_leaf
  1310. .lookup:
  1311.         stdcall edi, [_name+4], [_len]
  1312. .error:
  1313.         ret
  1314. endp
  1315.  
  1316.  
  1317. ; ZF/zf   = ok/fail
  1318. ; edx:eax = inode/garbage:error
  1319. proc xfs_get_inode uses ebx esi edi, _name
  1320.         ; call *._.get_inode_short until file is found / error returned
  1321.         ; start from the root inode
  1322.         mov     eax, [ebp+XFS.rootino.lo]
  1323.         mov     edx, [ebp+XFS.rootino.hi]
  1324.         mov     esi, [_name]
  1325. .next_dir:
  1326. @@:
  1327.         cmp     byte[esi], '/'
  1328.         jnz     @f
  1329.         inc     esi
  1330.         jmp     @b
  1331. @@:
  1332.         cmp     byte[esi], 0
  1333.         jz      .found
  1334.         push    esi
  1335.         inc     esi
  1336. @@:
  1337.         cmp     byte[esi], 0
  1338.         jz      @f
  1339.         cmp     byte[esi], '/'
  1340.         jz      @f
  1341.         inc     esi
  1342.         jmp     @b
  1343. @@:
  1344.         mov     ecx, esi
  1345.         sub     ecx, [esp]
  1346.         mov     [ebp+XFS.inode_self.lo], eax
  1347.         mov     [ebp+XFS.inode_self.hi], edx
  1348.         stdcall xfs._.get_inode_short, eax, edx, ecx      ; esi pushed above
  1349.         jz      .next_dir
  1350. .error:
  1351. .found:
  1352.         ret
  1353. endp
  1354.  
  1355.  
  1356. ; in:  ebp = pointer to XFS structure
  1357. ; in:  esi
  1358. ; in:  ebx = pointer to parameters from sysfunc 70
  1359. ; out: eax, ebx = return values for sysfunc 70
  1360. ; out: [edx] -- f70.1 out structure
  1361. proc xfs_ReadFolder uses esi edi
  1362.         call    xfs._.lock
  1363.         stdcall xfs_get_inode, esi
  1364.         jnz     .error
  1365.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
  1366.         test    eax, eax
  1367.         jnz     .error
  1368.         stdcall xfs._.readdir, [ebx+f70s1arg.start_idx], [ebx+f70s1arg.count], [ebx+f70s1arg.buf], edx, [ebx+f70s1arg.encoding]
  1369.         test    eax, eax
  1370.         jnz     .error
  1371.         mov     edx, [ebx+f70s1arg.buf]
  1372.         mov     ecx, [ebx+f70s1arg.count]
  1373.         cmp     [edx+bdfe_hdr.read_cnt], ecx
  1374.         jz      .quit
  1375.         movi    eax, ERROR_END_OF_FILE
  1376. .quit:
  1377.         mov     ebx, [edx+bdfe_hdr.read_cnt]
  1378.  
  1379. .error:
  1380.         push    eax
  1381.         call    xfs._.unlock
  1382.         pop     eax
  1383.         ret
  1384. endp
  1385.  
  1386.  
  1387. ; edx -- pointer to inode number in big endian
  1388. ; ZF -- must be set at exit
  1389. proc xfs._.get_inode_number_sf
  1390.         cmp     [ebx+xfs_dir2_sf.hdr.i8count], 0
  1391.         jz      .i4bytes
  1392. .i8bytes:
  1393.         movbe   eax, [edx+DQ.hi]
  1394.         movbe   edx, [edx+DQ.lo]
  1395.         ret
  1396. .i4bytes:
  1397.         movbe   eax, [edx+DQ.lo]
  1398.         xor     edx, edx
  1399.         ret
  1400. endp
  1401.  
  1402. proc xfs._.conv_time_to_kos_epoch
  1403.         movbe   eax, [ecx+DQ.hi_be]
  1404.         call    fsTime2bdfe
  1405.         ret
  1406. endp
  1407.  
  1408. proc xfs._.conv_bigtime_to_kos_epoch
  1409. NANOSEC_PER_SEC = 1_000_000_000
  1410. BIGTIME_TO_UNIX_OFFSET = 0x80000000     ; int32 min
  1411. UNIXTIME_TO_KOS_OFFSET = (365*31+8)*24*60*60  ; 01.01.1970--01.01.2001
  1412. BIGTIME_TO_KOS_OFFSET = BIGTIME_TO_UNIX_OFFSET + UNIXTIME_TO_KOS_OFFSET
  1413. BIGTIME_TO_KOS_OFFSET_NS = BIGTIME_TO_KOS_OFFSET * NANOSEC_PER_SEC
  1414.         movbe   edx, [ecx+DQ.hi_be]
  1415.         movbe   eax, [ecx+DQ.lo_be]
  1416.         sub     eax, BIGTIME_TO_KOS_OFFSET_NS AND 0xffffffff
  1417.         sbb     edx, BIGTIME_TO_KOS_OFFSET_NS SHR 32
  1418.         jnc     .after_kos_epoch_begin
  1419.         xor     eax, eax        ; set to very begin of kolibrios epoch
  1420.         xor     edx, edx
  1421.         jmp     .time_to_bdfe
  1422. .after_kos_epoch_begin:
  1423.         cmp     edx, NANOSEC_PER_SEC
  1424.         jb      .time_to_bdfe
  1425.         mov     edx, NANOSEC_PER_SEC - 1
  1426.         mov     eax, -1         ; very end of kolibrios epoch
  1427. .time_to_bdfe:
  1428.         mov     ecx, NANOSEC_PER_SEC
  1429.         div     ecx
  1430.         call    fsTime2bdfe
  1431.         ret
  1432. endp
  1433.  
  1434. proc xfs_get_inode_info uses ebx esi edi, _src, _dst
  1435.         ; get access time and other file properties
  1436.         ; useful for browsing directories
  1437.         ; called for each dir entry
  1438.         xor     eax, eax
  1439.         mov     esi, [_src]
  1440.         movzx   ecx, [esi+xfs_inode.di_core.di_mode]
  1441.         xchg    cl, ch
  1442.         test    ecx, S_IFDIR
  1443.         jz      @f
  1444.         movi    eax, 0x10       ; set directory flag
  1445. @@:
  1446.         mov     edi, [_dst]
  1447.         mov     [edi+bdfe.attr], eax
  1448.         movbe   edx, [esi+xfs_inode.di_core.di_size.hi_be]
  1449.         movbe   eax, [esi+xfs_inode.di_core.di_size.lo_be]
  1450.         mov     [edi+bdfe.size.hi], edx
  1451.         mov     [edi+bdfe.size.lo], eax
  1452.  
  1453.         add     edi, bdfe.ctime
  1454.         lea     ecx, [esi+xfs_inode.di_core.di_ctime]
  1455.         call    [ebp+XFS.conv_time_to_kos_epoch]
  1456.         lea     ecx, [esi+xfs_inode.di_core.di_atime]
  1457.         call    [ebp+XFS.conv_time_to_kos_epoch]
  1458.         lea     ecx, [esi+xfs_inode.di_core.di_mtime]
  1459.         call    [ebp+XFS.conv_time_to_kos_epoch]
  1460.  
  1461.         movi    eax, ERROR_SUCCESS
  1462.         cmp     esp, esp
  1463.         ret
  1464. endp
  1465.  
  1466.  
  1467. proc xfs._.extent_unpack uses eax ebx ecx edx, _extent_data
  1468.         ; extents come as packed 128bit bitfields
  1469.         ; unpack them to access internal fields
  1470.         ; write result to the XFS.extent structure
  1471.         mov     ebx, [_extent_data]
  1472.  
  1473.         xor     eax, eax
  1474.         movbe   edx, [ebx+0]
  1475.         test    edx, 0x80000000         ; mask, see documentation
  1476.         setnz   al
  1477.         mov     [ebp+XFS.extent.br_state], eax
  1478.  
  1479.         and     edx, 0x7fffffff         ; mask
  1480.         movbe   eax, [ebx+4]
  1481.         shrd    eax, edx, 9
  1482.         shr     edx, 9
  1483.         mov     [ebp+XFS.extent.br_startoff.lo], eax
  1484.         mov     [ebp+XFS.extent.br_startoff.hi], edx
  1485.  
  1486.         movbe   edx, [ebx+4]
  1487.         movbe   eax, [ebx+8]
  1488.         movbe   ecx, [ebx+12]
  1489.         and     edx, 0x000001ff         ; mask
  1490.         shrd    ecx, eax, 21
  1491.         shrd    eax, edx, 21
  1492.         mov     [ebp+XFS.extent.br_startblock.lo], ecx
  1493.         mov     [ebp+XFS.extent.br_startblock.hi], eax
  1494.  
  1495.         movbe   eax, [ebx+12]
  1496.         and     eax, 0x001fffff         ; mask
  1497.         mov     [ebp+XFS.extent.br_blockcount], eax
  1498.         ret
  1499. endp
  1500.  
  1501.  
  1502. proc xfs_hashname uses ecx esi, _name, _len
  1503.         xor     eax, eax
  1504.         mov     esi, [_name]
  1505.         mov     ecx, [_len]
  1506. @@:
  1507.         rol     eax, 7
  1508.         xor     al, [esi]
  1509.         add     esi, 1
  1510.         dec     ecx
  1511.         jnz     @b
  1512.         ret
  1513. endp
  1514.  
  1515.  
  1516. ; eax -- hash value
  1517. proc xfs._.get_addr_by_hash uses ebx esi, _base, _len
  1518.         ; look for the directory entry offset by its file name hash
  1519.         ; allows fast file search for block, leaf and node directories
  1520.         ; binary (ternary) search
  1521.         mov     ebx, [_base]
  1522.         mov     edx, [_len]
  1523. .next:
  1524.         mov     ecx, edx
  1525. ;        jecxz   .error
  1526.         test    ecx, ecx
  1527.         jz      .not_found
  1528.         shr     ecx, 1
  1529.         movbe   esi, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.hashval]
  1530.         cmp     eax, esi
  1531.         jb      .below
  1532.         ja      .above
  1533.         movbe   eax, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.address]
  1534.         ret
  1535. .below:
  1536.         mov     edx, ecx
  1537.         jmp     .next
  1538. .above:
  1539.         lea     ebx, [ebx+(ecx+1)*sizeof.xfs_dir2_leaf_entry]
  1540.         sub     edx, ecx
  1541.         dec     edx
  1542.         jmp     .next
  1543. .not_found:
  1544.         movi    eax, ERROR_FILE_NOT_FOUND
  1545.         test    esp, esp
  1546.         ret
  1547. endp
  1548.  
  1549.  
  1550. ;----------------------------------------------------------------
  1551. ; xfs_GetFileInfo: XFS implementation of getting file info
  1552. ; in:  ebp = pointer to XFS structure
  1553. ; in:  esi = name
  1554. ; in:  ebx = pointer to parameters from sysfunc 70
  1555. ; out: eax, ebx = return values for sysfunc 70
  1556. ;----------------------------------------------------------------
  1557. proc xfs_GetFileInfo uses ecx edx esi edi
  1558.         call    xfs._.lock
  1559.         stdcall xfs_get_inode, esi
  1560.         jnz     .error
  1561.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
  1562.         test    eax, eax
  1563.         movi    eax, ERROR_FS_FAIL
  1564.         jnz     .error
  1565.         stdcall xfs_get_inode_info, edx, [ebx+f70s5arg.buf]
  1566. .quit:
  1567.         call    xfs._.unlock
  1568.         xor     eax, eax
  1569.         ret
  1570. .error:
  1571.         push    eax
  1572.         call    xfs._.unlock
  1573.         pop     eax
  1574.         ret
  1575. endp
  1576.  
  1577.  
  1578. proc xfs._.file.read_extent uses ebx ecx edx, _callback, _callback_data
  1579.         mov     eax, [ebp+XFS.file_offset.lo]
  1580.         mov     edx, [ebp+XFS.file_offset.hi]
  1581.         mov     esi, [ebp+XFS.extent.br_startoff.lo]
  1582.         mov     edi, [ebp+XFS.extent.br_startoff.hi]
  1583.         mov     ecx, [ebp+XFS.blocklog]
  1584.         shld    edi, esi, cl
  1585.         shl     esi, cl
  1586.         cmp     edx, edi
  1587.         jb      .hole
  1588.         ja      .try_head
  1589.         cmp     eax, esi
  1590.         ja      .try_head
  1591.         jz      .try_match
  1592. .hole:
  1593.         sub     esi, eax
  1594.         sbb     edi, edx
  1595.         movi    ecx, -1
  1596.         test    edi, edi
  1597.         jnz     @f
  1598.         mov     ecx, esi
  1599. @@:
  1600.         cmp     ecx, [ebp+XFS.bytes_to_read]
  1601.         jbe     @f
  1602.         mov     ecx, [ebp+XFS.bytes_to_read]
  1603. @@:
  1604.         mov     edi, [ebp+XFS.file_buffer]
  1605.         xor     eax, eax
  1606.         sub     [ebp+XFS.bytes_to_read], ecx
  1607.         sub     [ebp+XFS.bytes_left_in_file.lo], ecx
  1608.         sbb     [ebp+XFS.bytes_left_in_file.hi], 0
  1609.         add     [ebp+XFS.bytes_read], ecx
  1610.         add     [ebp+XFS.file_buffer], ecx
  1611.         add     [ebp+XFS.file_offset.lo], ecx
  1612.         adc     [ebp+XFS.file_offset.hi], 0
  1613.         rep stosb
  1614.         cmp     [ebp+XFS.bytes_to_read], 0
  1615.         jz      .quit
  1616.         jmp     .try_match
  1617. .try_head:
  1618.         mov     eax, [ebp+XFS.file_offset.lo]
  1619.         mov     ecx, [ebp+XFS.blocksize]
  1620.         dec     ecx
  1621.         test    eax, ecx
  1622.         jz      .try_match
  1623. .head:
  1624.         mov     eax, [ebp+XFS.extent.br_startblock.lo]
  1625.         mov     edx, [ebp+XFS.extent.br_startblock.hi]
  1626.         mov     ebx, [ebp+XFS.cur_block_data]
  1627.         stdcall xfs._.read_block
  1628.         mov     esi, [ebp+XFS.cur_block_data]
  1629.         mov     edi, [ebp+XFS.file_buffer]
  1630.         mov     eax, [ebp+XFS.file_offset.lo]
  1631.         mov     ecx, [ebp+XFS.blocksize]
  1632.         dec     ecx
  1633.         and     eax, ecx
  1634.         add     esi, eax
  1635.         inc     ecx
  1636.         sub     ecx, eax
  1637.         cmp     ecx, [ebp+XFS.bytes_to_read]
  1638.         jbe     @f
  1639.         mov     ecx, [ebp+XFS.bytes_to_read]
  1640. @@:
  1641.         sub     [ebp+XFS.bytes_to_read], ecx
  1642.         sub     [ebp+XFS.bytes_left_in_file.lo], ecx
  1643.         sbb     [ebp+XFS.bytes_left_in_file.hi], 0
  1644.         add     [ebp+XFS.bytes_read], ecx
  1645.         add     [ebp+XFS.file_buffer], ecx
  1646.         add     [ebp+XFS.file_offset.lo], ecx
  1647.         adc     [ebp+XFS.file_offset.hi], 0
  1648.         rep movsb
  1649.         add     [ebp+XFS.extent.br_startoff.lo], 1
  1650.         adc     [ebp+XFS.extent.br_startoff.hi], 0
  1651.         add     [ebp+XFS.extent.br_startblock.lo], 1
  1652.         adc     [ebp+XFS.extent.br_startblock.hi], 0
  1653.         dec     [ebp+XFS.extent.br_blockcount]
  1654. ;        cmp     [ebp+XFS.bytes_to_read], 0
  1655.         jz      .quit
  1656. .try_match:
  1657.         mov     eax, [ebp+XFS.bytes_to_read]
  1658.         test    eax, eax
  1659.         jz      .quit
  1660.         cmp     eax, [ebp+XFS.blocksize]
  1661.         jb      .tail
  1662.         mov     ecx, [ebp+XFS.blocklog]
  1663.         shr     eax, cl
  1664.         cmp     eax, [ebp+XFS.extent.br_blockcount]
  1665.         jbe     @f
  1666.         mov     eax, [ebp+XFS.extent.br_blockcount]
  1667. @@:
  1668.         mov     ecx, eax
  1669.         mov     eax, [ebp+XFS.extent.br_startblock.lo]
  1670.         mov     edx, [ebp+XFS.extent.br_startblock.hi]
  1671.         mov     ebx, [ebp+XFS.file_buffer]
  1672.         push    ecx
  1673.         stdcall xfs._.read_blocks
  1674.         pop     eax
  1675.         add     [ebp+XFS.extent.br_startoff.lo], eax
  1676.         adc     [ebp+XFS.extent.br_startoff.hi], 0
  1677.         add     [ebp+XFS.extent.br_startblock.lo], eax
  1678.         adc     [ebp+XFS.extent.br_startblock.hi], 0
  1679.         sub     [ebp+XFS.extent.br_blockcount], eax
  1680.         imul    eax, [ebp+XFS.blocksize]
  1681.         sub     [ebp+XFS.bytes_to_read], eax
  1682.         sub     [ebp+XFS.bytes_left_in_file.lo], eax
  1683.         sbb     [ebp+XFS.bytes_left_in_file.hi], 0
  1684.         add     [ebp+XFS.bytes_read], eax
  1685.         add     [ebp+XFS.file_buffer], eax
  1686.         add     [ebp+XFS.file_offset.lo], eax
  1687.         adc     [ebp+XFS.file_offset.hi], 0
  1688. ;        cmp     [ebp+XFS.bytes_to_read], 0
  1689.         cmp     [ebp+XFS.extent.br_blockcount], 0
  1690.         jz      .quit
  1691. .tail:
  1692.         mov     eax, [ebp+XFS.extent.br_startblock.lo]
  1693.         mov     edx, [ebp+XFS.extent.br_startblock.hi]
  1694.         mov     ebx, [ebp+XFS.cur_block_data]
  1695.         stdcall xfs._.read_block
  1696.         mov     ecx, [ebp+XFS.bytes_to_read]
  1697.         cmp     [ebp+XFS.bytes_left_in_file.hi], 0
  1698.         jnz     @f
  1699.         cmp     ecx, [ebp+XFS.bytes_left_in_file.lo]
  1700.         jbe     @f
  1701.         mov     ecx, [ebp+XFS.bytes_left_in_file.lo]
  1702. @@:
  1703.         mov     esi, [ebp+XFS.cur_block_data]
  1704.         mov     edi, [ebp+XFS.file_buffer]
  1705.         mov     eax, ecx
  1706.         rep movsb
  1707.         add     [ebp+XFS.bytes_read], eax
  1708.         sub     [ebp+XFS.bytes_to_read], eax
  1709.         sub     [ebp+XFS.bytes_left_in_file.lo], eax
  1710.         sbb     [ebp+XFS.bytes_left_in_file.hi], 0
  1711.         add     [ebp+XFS.file_buffer], eax
  1712.         add     [ebp+XFS.file_offset.lo], eax
  1713.         adc     [ebp+XFS.file_offset.hi], 0
  1714.         add     [ebp+XFS.extent.br_startoff.lo], 1
  1715.         adc     [ebp+XFS.extent.br_startoff.hi], 0
  1716.         add     [ebp+XFS.extent.br_startblock.lo], 1
  1717.         adc     [ebp+XFS.extent.br_startblock.hi], 0
  1718.         dec     [ebp+XFS.extent.br_blockcount]
  1719. .quit:
  1720.         mov     esi, [ebp+XFS.extent.br_startoff.lo]
  1721.         mov     edi, [ebp+XFS.extent.br_startoff.hi]
  1722.         movi    eax, ERROR_SUCCESS
  1723.         cmp     esp, esp
  1724.         ret
  1725. endp
  1726.  
  1727.  
  1728. ;----------------------------------------------------------------
  1729. ; in:  ebp = pointer to XFS structure
  1730. ; in:  esi = name
  1731. ; in:  ebx = pointer to parameters from sysfunc 70
  1732. ; out: eax, ebx = return values for sysfunc 70
  1733. ;----------------------------------------------------------------
  1734. proc xfs_Read uses ecx edx esi edi
  1735. locals
  1736.         .offset_begin DQ ?
  1737.         .offset_end   DQ ?
  1738. endl
  1739.         call    xfs._.lock
  1740.         mov     [ebp+XFS.bytes_read], 0
  1741.         mov     eax, [ebx+f70s0arg.count]
  1742.         mov     [ebp+XFS.bytes_to_read], eax
  1743.         test    eax, eax
  1744.         jz      .quit
  1745.         mov     eax, [ebx+f70s0arg.buf]
  1746.         mov     [ebp+XFS.file_buffer], eax
  1747.         mov     eax, [ebx+f70s0arg.offset.hi]
  1748.         mov     [ebp+XFS.file_offset.hi], eax
  1749.         mov     eax, [ebx+f70s0arg.offset.lo]
  1750.         mov     [ebp+XFS.file_offset.lo], eax
  1751.  
  1752.         stdcall xfs_get_inode, esi
  1753.         jnz     .error
  1754.         stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
  1755.         test    eax, eax
  1756.         movi    eax, ERROR_FS_FAIL
  1757.         jnz     .error
  1758.         mov     [ebp+XFS.cur_inode_save], edx
  1759.         mov     ebx, edx
  1760.         ; precompute .offset_begin
  1761.         mov     esi, [ebp+XFS.file_offset.lo]
  1762.         mov     edi, [ebp+XFS.file_offset.hi]
  1763.         mov     ecx, [ebp+XFS.blocklog]
  1764.         shrd    esi, edi, cl
  1765.         shr     edi, cl
  1766.         mov     [.offset_begin.lo], esi
  1767.         mov     [.offset_begin.hi], edi
  1768.         ; precompute .offset_end
  1769.         mov     esi, [ebp+XFS.file_offset.lo]
  1770.         mov     edi, [ebp+XFS.file_offset.hi]
  1771.         add     esi, [ebp+XFS.bytes_to_read]
  1772.         adc     edi, 0
  1773.         mov     ecx, [ebp+XFS.blocksize]
  1774.         dec     ecx
  1775.         add     esi, ecx
  1776.         adc     edi, 0
  1777.         mov     ecx, [ebp+XFS.blocklog]
  1778.         shrd    esi, edi, cl
  1779.         shr     edi, cl
  1780.         mov     [.offset_end.lo], esi
  1781.         mov     [.offset_end.hi], edi
  1782.  
  1783.         movbe   ecx, [ebx+xfs_inode.di_core.di_size.hi]
  1784.         movbe   edx, [ebx+xfs_inode.di_core.di_size.lo]
  1785.         mov     [ebp+XFS.bytes_left_in_file.lo], ecx
  1786.         mov     [ebp+XFS.bytes_left_in_file.hi], edx
  1787.  
  1788.         sub     ecx, [ebp+XFS.file_offset.lo]
  1789.         sbb     edx, [ebp+XFS.file_offset.hi]
  1790.         movi    eax, ERROR_END_OF_FILE
  1791.         jb      .error
  1792.         mov     [ebp+XFS.eof], 0
  1793.         test    edx, edx
  1794.         jnz     @f
  1795.         cmp     ecx, [ebp+XFS.bytes_to_read]
  1796.         jae     @f
  1797.         mov     [ebp+XFS.eof], ERROR_END_OF_FILE
  1798.         mov     [ebp+XFS.bytes_to_read], ecx
  1799. @@:
  1800.  
  1801.         cmp     [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
  1802.         jz      .btree
  1803. .extent_list:
  1804.         mov     eax, ebx
  1805.         add     eax, [ebp+XFS.inode_core_size]
  1806.         mov     edx, [ebp+XFS.nextents_offset]
  1807.         movbe   edx, [ebx+edx]
  1808.         mov     ecx, [.offset_begin.lo]
  1809.         mov     [ebp+XFS.offset_begin.lo], ecx
  1810.         mov     ecx, [.offset_begin.hi]
  1811.         mov     [ebp+XFS.offset_begin.hi], ecx
  1812.         mov     ecx, [.offset_end.lo]
  1813.         mov     [ebp+XFS.offset_end.lo], ecx
  1814.         mov     ecx, [.offset_end.hi]
  1815.         mov     [ebp+XFS.offset_end.hi], ecx
  1816.         stdcall xfs._.walk_extent_list, edx, eax, xfs._.file.read_extent, 0, 0
  1817.         jnz     .error
  1818.         jmp     .hole_check
  1819. .btree:
  1820.         mov     eax, [ebp+XFS.inodesize]
  1821.         sub     eax, [ebp+XFS.inode_core_size]
  1822.         movzx   ecx, [ebx+xfs_inode.di_core.di_forkoff]
  1823.         jecxz   @f
  1824.         shl     ecx, 3
  1825.         mov     eax, ecx
  1826. @@:
  1827.         mov     edx, ebx
  1828.         add     edx, [ebp+XFS.inode_core_size]
  1829.         mov     ecx, [.offset_begin.lo]
  1830.         mov     [ebp+XFS.offset_begin.lo], ecx
  1831.         mov     ecx, [.offset_begin.hi]
  1832.         mov     [ebp+XFS.offset_begin.hi], ecx
  1833.         mov     ecx, [.offset_end.lo]
  1834.         mov     [ebp+XFS.offset_end.lo], ecx
  1835.         mov     ecx, [.offset_end.hi]
  1836.         mov     [ebp+XFS.offset_end.hi], ecx
  1837.         stdcall xfs._.walk_btree, edx, eax, xfs._.file.read_extent, 0, 0, 1
  1838. .hole_check:
  1839.         cmp     [ebp+XFS.bytes_left_in_file.hi], 0
  1840.         jnz     @f
  1841.         cmp     [ebp+XFS.bytes_left_in_file.lo], 0
  1842.         jz      .hole_done
  1843. @@:
  1844.         cmp     [ebp+XFS.bytes_to_read], 0
  1845.         jz      .hole_done
  1846.         mov     ebx, [ebp+XFS.cur_inode_save]
  1847.         movbe   edx, [ebx+xfs_inode.di_core.di_size.lo]
  1848.         movbe   eax, [ebx+xfs_inode.di_core.di_size.hi]
  1849.         sub     eax, [ebp+XFS.file_offset.lo]
  1850.         sbb     edx, [ebp+XFS.file_offset.hi]
  1851.         jc      .hole_done
  1852.         mov     ecx, [ebp+XFS.bytes_to_read]
  1853.         test    edx, edx
  1854.         jnz     .hole_read
  1855.         cmp     eax, [ebp+XFS.bytes_to_read]
  1856.         jae     .hole_read
  1857.         mov     ecx, eax
  1858.         jmp     .hole_read
  1859. .hole_read:
  1860.         sub     [ebp+XFS.bytes_to_read], ecx
  1861.         add     [ebp+XFS.bytes_read], ecx
  1862.         mov     edi, [ebp+XFS.file_buffer]
  1863.         xor     eax, eax
  1864.         rep stosb
  1865. .hole_done:
  1866. .quit:
  1867.         mov     eax, [ebp+XFS.eof]
  1868. .error:
  1869.         push    eax
  1870.         call    xfs._.unlock
  1871.         pop     eax
  1872.         mov     ebx, [ebp+XFS.bytes_read]
  1873.         ret
  1874. endp
  1875.  
  1876.  
  1877. proc xfs._.leafn_calc_entries uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
  1878.         mov     edx, [_cur_dirblock]
  1879.         movzx   eax, [ebp+XFS.da_node_magic]
  1880.         cmp     [edx+xfs_dir2_leaf.hdr.info.magic], ax
  1881.         jz      .quit
  1882.         cmp     [ebp+XFS.version], 5
  1883.         jnz     @f
  1884.         add     edx, xfs_dir3_leaf.hdr.count-xfs_dir2_leaf.hdr.count
  1885. @@:
  1886.         movzx   eax, [edx+xfs_dir2_leaf.hdr.count]
  1887.         movzx   ecx, [edx+xfs_dir2_leaf.hdr.stale]
  1888.         xchg    al, ah
  1889.         xchg    cl, ch
  1890.         sub     eax, ecx
  1891.         add     [ebp+XFS.entries_read], eax
  1892. .quit:
  1893.         movi    eax, ERROR_SUCCESS
  1894.         cmp     esp, esp
  1895.         ret
  1896. endp
  1897.  
  1898.  
  1899. proc xfs._.get_before_by_hashval uses ebx edx esi edi, _base, _count, _hash
  1900.         mov     edi, [_hash]
  1901.         mov     edx, [_count]
  1902.         xor     ecx, ecx
  1903. .node.next:
  1904.         movbe   eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
  1905.         cmp     [ebp+XFS.version], 5
  1906.         jnz     @f
  1907.         movbe   eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
  1908. @@:
  1909.         cmp     eax, edi
  1910.         jae     .node.leaf_found
  1911.         inc     ecx
  1912.         cmp     ecx, edx
  1913.         jnz     .node.next
  1914.         movi    eax, ERROR_FILE_NOT_FOUND
  1915.         test    esp, esp
  1916.         jmp     .error
  1917. .node.leaf_found:
  1918.         movbe   eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
  1919.         cmp     [ebp+XFS.version], 5
  1920.         jnz     @f
  1921.         movbe   eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
  1922. @@:
  1923.         jmp     .quit
  1924. .error:
  1925.         test    esp, esp
  1926.         ret
  1927. .quit:
  1928.         cmp     esp, esp
  1929.         ret
  1930. endp
  1931.  
  1932.  
  1933. proc xfs._.long_btree.seek uses ebx esi edi, _ptr, _size
  1934.         mov     ebx, [_ptr]
  1935.         mov     esi, [_size]
  1936.         sub     esi, sizeof.xfs_bmdr_block
  1937.         shr     esi, 4
  1938.         shl     esi, 3
  1939.         movzx   eax, [ebx+xfs_bmdr_block.bb_level]
  1940.         movzx   ecx, [ebx+xfs_bmdr_block.bb_numrecs]
  1941.         xchg    cl, ch
  1942.         add     ebx, sizeof.xfs_bmdr_block
  1943.         jmp     .common
  1944. .not_root:
  1945.         mov     esi, [ebp+XFS.blocksize]
  1946.         sub     esi, [ebp+XFS.bmbt_block_size]
  1947.         shr     esi, 4
  1948.         shl     esi, 3
  1949.         movzx   eax, [ebx+xfs_bmbt_block.bb_level]
  1950.         movzx   ecx, [ebx+xfs_bmbt_block.bb_numrecs]
  1951.         xchg    cl, ch
  1952.         add     ebx, [ebp+XFS.bmbt_block_size]
  1953. .common:
  1954.         test    eax, eax
  1955.         jz      .leaf
  1956. .node:
  1957. .next_rec:
  1958.         dec     ecx
  1959.         js      .error
  1960.         movbe   eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.lo]
  1961.         cmp     [ebp+XFS.offset_begin.hi], eax
  1962.         ja      .node_found
  1963.         jb      .next_rec
  1964.         movbe   eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.hi]
  1965.         cmp     [ebp+XFS.offset_begin.lo], eax
  1966.         jae     .node_found
  1967.         jmp     .next_rec
  1968. .node_found:
  1969.         add     ebx, esi
  1970.         movbe   edx, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.lo]
  1971.         movbe   eax, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.hi]
  1972.         mov     ebx, [ebp+XFS.cur_block]
  1973.         stdcall xfs._.read_block
  1974.         test    eax, eax
  1975.         jnz     .error
  1976.         mov     ebx, [ebp+XFS.cur_block]
  1977.         jmp     .not_root
  1978. .leaf:
  1979.         jmp     .quit
  1980. .error:
  1981. .quit:
  1982.         ret
  1983. endp
  1984.  
  1985.  
  1986. proc xfs._.walk_btree uses ebx esi edi, _ptr, _size, _callback_extent, _callback_block, _callback_data, _is_root
  1987.         stdcall xfs._.long_btree.seek, [_ptr+4], [_size]
  1988.         mov     [_is_root], 0
  1989. .begin:
  1990.         mov     ebx, [ebp+XFS.cur_block]
  1991.         mov     eax, [ebp+XFS.bmap_magic]
  1992.         cmp     [ebx+xfs_bmbt_block.bb_magic], eax
  1993.         movi    eax, ERROR_FS_FAIL
  1994.         jnz     .error
  1995.         movzx   ecx, [ebx+xfs_bmbt_block.bb_numrecs]
  1996.         xchg    cl, ch
  1997.         add     ebx, [ebp+XFS.bmbt_block_size]
  1998.         stdcall xfs._.walk_extent_list, ecx, ebx, [_callback_extent+8], [_callback_block+4], [_callback_data]
  1999.         jnz     .error
  2000.         mov     esi, [ebp+XFS.offset_begin.lo]
  2001.         mov     edi, [ebp+XFS.offset_begin.hi]
  2002.         cmp     edi, [ebp+XFS.offset_end.hi]
  2003.         ja      .quit
  2004.         cmp     esi, [ebp+XFS.offset_end.lo]
  2005.         jae     .quit
  2006.         sub     ebx, [ebp+XFS.bmbt_block_size]
  2007.         movbe   edx, [ebx+xfs_bmbt_block.bb_rightsib.lo]
  2008.         movbe   eax, [ebx+xfs_bmbt_block.bb_rightsib.hi]
  2009.         mov     ecx, eax
  2010.         and     ecx, edx
  2011.         inc     ecx
  2012.         jz      .quit
  2013.         mov     ebx, [ebp+XFS.cur_block]
  2014.         stdcall xfs._.read_block
  2015.         jnz     .error
  2016.         jmp     .begin
  2017. .error:
  2018. .quit:
  2019.         ret
  2020. endp
  2021.  
  2022.  
  2023. proc xfs._.btree_read_block uses ebx esi edi, _tree, _size, _block_lo, _block_hi, _buf
  2024.         mov     eax, [_block_lo]
  2025.         mov     [ebp+XFS.offset_begin.lo], eax
  2026.         mov     eax, [_block_hi]
  2027.         mov     [ebp+XFS.offset_begin.hi], eax
  2028.         stdcall xfs._.long_btree.seek, [_tree+4], [_size]
  2029.         jnz     .error
  2030.         mov     ebx, [ebp+XFS.cur_block]
  2031.         mov     eax, [ebp+XFS.bmap_magic]
  2032.         cmp     [ebx+xfs_bmbt_block.bb_magic], eax
  2033.         jnz     .error
  2034.         movzx   ecx, [ebx+xfs_bmbt_block.bb_numrecs]
  2035.         xchg    cl, ch
  2036.         add     ebx, [ebp+XFS.bmbt_block_size]
  2037.         mov     eax, [_block_lo]
  2038.         mov     [ebp+XFS.offset_begin.lo], eax
  2039.         mov     eax, [_block_hi]
  2040.         mov     [ebp+XFS.offset_begin.hi], eax
  2041.         stdcall xfs._.extent_list.seek, ecx
  2042.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], \
  2043.                 [ebp+XFS.extent.br_startblock.hi], [_buf]
  2044. .error:
  2045. .quit:
  2046.         ret
  2047. endp
  2048.  
  2049.  
  2050. proc xfs._.extent_list.seek uses esi, _count
  2051.         sub     ebx, sizeof.xfs_bmbt_rec
  2052.         inc     [_count]
  2053. .find_low:
  2054.         add     ebx, sizeof.xfs_bmbt_rec
  2055.         dec     [_count]
  2056.         jz      .quit
  2057.         stdcall xfs._.extent_unpack, ebx
  2058.         mov     eax, [ebp+XFS.extent.br_startoff.lo]
  2059.         mov     edx, [ebp+XFS.extent.br_startoff.hi]
  2060.         mov     esi, [ebp+XFS.extent.br_blockcount]
  2061.         add     eax, esi
  2062.         adc     edx, 0
  2063.  
  2064.         cmp     edx, [ebp+XFS.offset_begin.hi]
  2065.         ja      .low_found
  2066.         jb      .find_low
  2067.         cmp     eax, [ebp+XFS.offset_begin.lo]
  2068.         ja      .low_found
  2069.         jmp     .find_low
  2070. .low_found:
  2071.         add     ebx, sizeof.xfs_bmbt_rec
  2072.  
  2073.         mov     eax, [ebp+XFS.offset_begin.lo]
  2074.         mov     edx, [ebp+XFS.offset_begin.hi]
  2075.         mov     esi, eax
  2076.         sub     esi, [ebp+XFS.extent.br_startoff.lo]
  2077.         jbe     .quit
  2078.         ; same br_blockcount for block and dirblock?
  2079.         mov     [ebp+XFS.extent.br_startoff.lo], eax
  2080.         mov     [ebp+XFS.extent.br_startoff.hi], edx
  2081.         sub     [ebp+XFS.extent.br_blockcount], esi
  2082.         add     [ebp+XFS.extent.br_startblock.lo], esi
  2083.         adc     [ebp+XFS.extent.br_startblock.hi], 0
  2084.         jmp     .quit
  2085. .quit:
  2086.         mov     eax, [_count]
  2087.         ret
  2088. endp
  2089.  
  2090.  
  2091. proc xfs._.extent_iterate_dirblocks _callback, _callback_data
  2092. .check_high:
  2093.         cmp     edi, [ebp+XFS.offset_end.hi]
  2094.         ja      .quit
  2095.         jb      .read_dirblock
  2096.         cmp     esi, [ebp+XFS.offset_end.lo]
  2097.         jae     .quit
  2098. .read_dirblock:
  2099.         stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
  2100.         mov     edx, [ebp+XFS.cur_dirblock]
  2101.         mov     eax, [_callback]
  2102.         stdcall eax, edx, esi, edi, [_callback_data]
  2103.         test    eax, eax
  2104.         jnz     .error
  2105.         mov     eax, [ebp+XFS.blkpdirblk]
  2106.         add     esi, eax
  2107.         adc     edi, 0
  2108.         add     [ebp+XFS.extent.br_startblock.lo], eax
  2109.         adc     [ebp+XFS.extent.br_startblock.hi], 0
  2110.         sub     [ebp+XFS.extent.br_blockcount], eax
  2111.         jnz     .check_high
  2112. .error:
  2113. .quit:
  2114.         ret
  2115. endp
  2116.  
  2117.  
  2118. proc xfs._.walk_extent_list uses ebx esi edi, _count, _ptr, _callback_extent, _callback_block, _callback_data
  2119.         mov     ebx, [_ptr]
  2120.         stdcall xfs._.extent_list.seek, [_count]
  2121.         mov     [_count], eax
  2122.         dec     [_count]
  2123.         js      .quit
  2124.         jmp     .next_extent.decoded
  2125. .next_extent:
  2126.         stdcall xfs._.extent_unpack, ebx
  2127.         add     ebx, sizeof.xfs_bmbt_rec
  2128. .next_extent.decoded:
  2129.         mov     eax, [ebp+XFS.extent.br_blockcount]
  2130.         add     [ebp+XFS.offset_begin.lo], eax
  2131.         adc     [ebp+XFS.offset_begin.hi], 0
  2132.         mov     esi, [ebp+XFS.extent.br_startoff.lo]
  2133.         mov     edi, [ebp+XFS.extent.br_startoff.hi]
  2134.         stdcall [_callback_extent+8], [_callback_block+4], [_callback_data]
  2135.         jnz     .error
  2136.         cmp     edi, [ebp+XFS.offset_end.hi]
  2137.         ja      .quit
  2138.         jb      @f
  2139.         cmp     esi, [ebp+XFS.offset_end.lo]
  2140.         jae     .quit
  2141. @@:
  2142.         dec     [_count]
  2143.         js      .quit
  2144.         jmp     .next_extent
  2145. .quit:
  2146.         movi    eax, ERROR_SUCCESS
  2147. .error:
  2148.         test    eax, eax
  2149.         ret
  2150. endp
  2151.  
  2152.  
  2153. proc xfs._.get_last_dirblock uses ecx
  2154.         mov     eax, [ebp+XFS.nextents_offset]
  2155.         movbe   eax, [ebx+eax]
  2156. assert (sizeof.xfs_bmbt_rec AND (sizeof.xfs_bmbt_rec - 1)) = 0
  2157.         shl     eax, BSF sizeof.xfs_bmbt_rec
  2158.         add     eax, [ebp+XFS.inode_core_size]
  2159.         lea     eax, [ebx+eax-sizeof.xfs_bmbt_rec]
  2160.         stdcall xfs._.extent_unpack, eax
  2161.         xor     edx, edx
  2162.         mov     eax, [ebp+XFS.extent.br_blockcount]
  2163.         mov     ecx, [ebp+XFS.dirblklog]
  2164.         shr     eax, cl
  2165.         dec     eax
  2166.         add     eax, [ebp+XFS.extent.br_startoff.lo]
  2167.         adc     edx, [ebp+XFS.extent.br_startoff.hi]
  2168.         ret
  2169. endp
  2170.  
  2171.  
  2172. restore prologue@proc,epilogue@proc
  2173. restore movbe
  2174.