Subversion Repositories Kolibri OS

Rev

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