Subversion Repositories Kolibri OS

Rev

Rev 5089 | Rev 7736 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 5363 $
  9.  
  10.  
  11. include 'xfs.inc'
  12.  
  13. ;
  14. ; This file contains XFS related code.
  15. ; For more information on XFS check sources below.
  16. ;
  17. ; 1. XFS Filesystem Structure, 2nd Edition, Revision 1. Silicon Graphics Inc. 2006
  18. ; 2. Linux source http://kernel.org
  19. ;
  20.  
  21.  
  22. ; test partition type (valid XFS one?)
  23. ; alloc and fill XFS (see xfs.inc) structure
  24. ; this function is called for each partition
  25. ; returns 0 (not XFS or invalid) / pointer to partition structure
  26. xfs_create_partition:
  27.         push    ebx ecx edx esi edi
  28.         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
  29.         jnz     .error
  30.         cmp     dword[ebx + xfs_sb.sb_magicnum], XFS_SB_MAGIC   ; signature
  31.         jne     .error
  32.  
  33.         ; TODO: check XFS.versionnum and XFS.features2
  34.         ;       print superblock params for debugging (waiting for bug reports)
  35.  
  36.         movi    eax, sizeof.XFS
  37.         call    malloc
  38.         test    eax, eax
  39.         jz      .error
  40.  
  41.         ; standard partition initialization, common for all file systems
  42.  
  43.         mov     edi, eax
  44.         mov     eax, dword[ebp + PARTITION.FirstSector]
  45.         mov     dword[edi + XFS.FirstSector], eax
  46.         mov     eax, dword[ebp + PARTITION.FirstSector + 4]
  47.         mov     dword[edi + XFS.FirstSector + 4], eax
  48.         mov     eax, dword[ebp + PARTITION.Length]
  49.         mov     dword[edi + XFS.Length], eax
  50.         mov     eax, dword[ebp + PARTITION.Length + 4]
  51.         mov     dword[edi + XFS.Length + 4], eax
  52.         mov     eax, [ebp + PARTITION.Disk]
  53.         mov     [edi + XFS.Disk], eax
  54.         mov     [edi + XFS.FSUserFunctions], xfs_user_functions
  55.  
  56.         ; here we initialize only one mutex so far (for the entire partition)
  57.         ; XFS potentially allows parallel r/w access to several AGs, keep it in mind for SMP times
  58.  
  59.         lea     ecx, [edi + XFS.Lock]
  60.         call    mutex_init
  61.  
  62.         ; read superblock and fill just allocated XFS partition structure
  63.  
  64.         mov     eax, [ebx + xfs_sb.sb_blocksize]
  65.         bswap   eax                                     ; XFS is big endian
  66.         mov     [edi + XFS.blocksize], eax
  67.         movzx   eax, word[ebx + xfs_sb.sb_sectsize]
  68.         xchg    al, ah
  69.         mov     [edi + XFS.sectsize], eax
  70.         movzx   eax, word[ebx + xfs_sb.sb_versionnum]
  71.         xchg    al, ah
  72.         mov     [edi + XFS.versionnum], eax
  73.         mov     eax, [ebx + xfs_sb.sb_features2]
  74.         bswap   eax
  75.         mov     [edi + XFS.features2], eax
  76.         movzx   eax, word[ebx + xfs_sb.sb_inodesize]
  77.         xchg    al, ah
  78.         mov     [edi + XFS.inodesize], eax
  79.         movzx   eax, word[ebx + xfs_sb.sb_inopblock]    ; inodes per block
  80.         xchg    al, ah
  81.         mov     [edi + XFS.inopblock], eax
  82.         movzx   eax, byte[ebx + xfs_sb.sb_blocklog]     ; log2 of block size, in bytes
  83.         mov     [edi + XFS.blocklog], eax
  84.         movzx   eax, byte[ebx + xfs_sb.sb_sectlog]
  85.         mov     [edi + XFS.sectlog], eax
  86.         movzx   eax, byte[ebx + xfs_sb.sb_inodelog]
  87.         mov     [edi + XFS.inodelog], eax
  88.         movzx   eax, byte[ebx + xfs_sb.sb_inopblog]
  89.         mov     [edi + XFS.inopblog], eax
  90.         movzx   eax, byte[ebx + xfs_sb.sb_dirblklog]
  91.         mov     [edi + XFS.dirblklog], eax
  92.         mov     eax, dword[ebx + xfs_sb.sb_rootino + 4] ;
  93.         bswap   eax                                     ; big
  94.         mov     dword[edi + XFS.rootino + 0], eax       ; endian
  95.         mov     eax, dword[ebx + xfs_sb.sb_rootino + 0] ; 64bit
  96.         bswap   eax                                     ; number
  97.         mov     dword[edi + XFS.rootino + 4], eax       ;
  98.  
  99.         mov     eax, [edi + XFS.blocksize]
  100.         mov     ecx, [edi + XFS.dirblklog]
  101.         shl     eax, cl
  102.         mov     [edi + XFS.dirblocksize], eax           ; blocks for files, dirblocks for directories
  103.  
  104.         ; sector is always smaller than block
  105.         ; so precalculate shift order to allow faster sector_num->block_num conversion
  106.  
  107.         mov     ecx, [edi + XFS.blocklog]
  108.         sub     ecx, [edi + XFS.sectlog]
  109.         mov     [edi + XFS.blockmsectlog], ecx
  110.  
  111.         mov     eax, 1
  112.         shl     eax, cl
  113.         mov     [edi + XFS.sectpblock], eax
  114.  
  115.         ; shift order for inode_num->block_num conversion
  116.  
  117.         mov     eax, [edi + XFS.blocklog]
  118.         sub     eax, [edi + XFS.inodelog]
  119.         mov     [edi + XFS.inodetoblocklog], eax
  120.  
  121.         mov     eax, [ebx + xfs_sb.sb_agblocks]
  122.         bswap   eax
  123.         mov     [edi + XFS.agblocks], eax
  124.         movzx   ecx, byte[ebx + xfs_sb.sb_agblklog]
  125.         mov     [edi + XFS.agblklog], ecx
  126.  
  127.         ; get the mask for block numbers
  128.         ; block numbers are AG relative!
  129.         ; bitfield length may vary between partitions
  130.  
  131.         mov     eax, 1
  132.         shl     eax, cl
  133.         dec     eax
  134.         mov     dword[edi + XFS.agblockmask + 0], eax
  135.         mov     eax, 1
  136.         sub     ecx, 32
  137.         jc      @f
  138.         shl     eax, cl
  139.     @@:
  140.         dec     eax
  141.         mov     dword[edi + XFS.agblockmask + 4], eax
  142.  
  143.         ; calculate magic offsets for directories
  144.  
  145.         mov     ecx, [edi + XFS.blocklog]
  146.         mov     eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff        ; lo
  147.         mov     edx, XFS_DIR2_LEAF_OFFSET SHR 32                ; hi
  148.         shrd    eax, edx, cl
  149.         mov     [edi + XFS.dir2_leaf_offset_blocks], eax
  150.  
  151.         mov     ecx, [edi + XFS.blocklog]
  152.         mov     eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff        ; lo
  153.         mov     edx, XFS_DIR2_FREE_OFFSET SHR 32                ; hi
  154.         shrd    eax, edx, cl
  155.         mov     [edi + XFS.dir2_free_offset_blocks], eax
  156.  
  157. ;        mov     ecx, [edi + XFS.dirblklog]
  158. ;        mov     eax, [edi + XFS.blocksize]
  159. ;        shl     eax, cl
  160. ;        mov     [edi + XFS.dirblocksize], eax
  161.  
  162.         mov     eax, [edi + XFS.blocksize]
  163.         call    malloc
  164.         test    eax, eax
  165.         jz      .error
  166.         mov     [edi + XFS.cur_block], eax
  167.  
  168.         ; we do need XFS.blocksize bytes for single inode
  169.         ; minimal file system structure is block, inodes are packed in blocks
  170.  
  171.         mov     eax, [edi + XFS.blocksize]
  172.         call    malloc
  173.         test    eax, eax
  174.         jz      .error
  175.         mov     [edi + XFS.cur_inode], eax
  176.  
  177.         ; temporary inode
  178.         ; used for browsing directories
  179.  
  180.         mov     eax, [edi + XFS.blocksize]
  181.         call    malloc
  182.         test    eax, eax
  183.         jz      .error
  184.         mov     [edi + XFS.tmp_inode], eax
  185.  
  186.         ; current sector
  187.         ; only for sector size structures like AGI
  188.         ; inodes has usually the same size, but never store them here
  189.  
  190.         mov     eax, [edi + XFS.sectsize]
  191.         call    malloc
  192.         test    eax, eax
  193.         jz      .error
  194.         mov     [edi + XFS.cur_sect], eax
  195.  
  196.         ; current directory block
  197.  
  198.         mov     eax, [edi + XFS.dirblocksize]
  199.         call    malloc
  200.         test    eax, eax
  201.         jz      .error
  202.         mov     [edi + XFS.cur_dirblock], eax
  203.  
  204.   .quit:
  205.         mov     eax, edi                ; return pointer to allocated XFS partition structure
  206.         pop     edi esi edx ecx ebx
  207.         ret
  208.   .error:
  209.         xor     eax, eax
  210.         pop     edi esi edx ecx ebx
  211.         ret
  212.  
  213.  
  214. iglobal
  215. align 4
  216. xfs_user_functions:
  217.         dd      xfs_free
  218.         dd      (xfs_user_functions_end - xfs_user_functions - 4) / 4
  219.         dd      xfs_Read
  220.         dd      xfs_ReadFolder
  221.         dd      0;xfs_Rewrite
  222.         dd      0;xfs_Write
  223.         dd      0;xfs_SetFileEnd
  224.         dd      xfs_GetFileInfo
  225.         dd      0;xfs_SetFileInfo
  226.         dd      0
  227.         dd      0;xfs_Delete
  228.         dd      0;xfs_CreateFolder
  229. xfs_user_functions_end:
  230. endg
  231.  
  232.  
  233. ; lock partition access mutex
  234. proc xfs_lock
  235. ;DEBUGF 1,"xfs_lock\n"
  236.         lea     ecx, [ebp + XFS.Lock]
  237.         jmp     mutex_lock
  238. endp
  239.  
  240.  
  241. ; unlock partition access mutex
  242. proc xfs_unlock
  243. ;DEBUGF 1,"xfs_unlock\n"
  244.         lea     ecx, [ebp + XFS.Lock]
  245.         jmp     mutex_unlock
  246. endp
  247.  
  248.  
  249. ; free all the allocated memory
  250. ; called on partition destroy
  251. proc xfs_free
  252.         push    ebp
  253.         xchg    ebp, eax
  254.         stdcall kernel_free, [ebp + XFS.cur_block]
  255.         stdcall kernel_free, [ebp + XFS.cur_inode]
  256.         stdcall kernel_free, [ebp + XFS.cur_sect]
  257.         stdcall kernel_free, [ebp + XFS.cur_dirblock]
  258.         stdcall kernel_free, [ebp + XFS.tmp_inode]
  259.         xchg    ebp, eax
  260.         call    free
  261.         pop     ebp
  262.         ret
  263. endp
  264.  
  265.  
  266. ;---------------------------------------------------------------
  267. ; block number (AG relative)
  268. ; eax -- inode_lo
  269. ; edx -- inode_hi
  270. ; ebx -- buffer
  271. ;---------------------------------------------------------------
  272. xfs_read_block:
  273.         push    ebx esi
  274.  
  275.         push    edx
  276.         push    eax
  277.  
  278.         ; XFS block numbers are AG relative
  279.         ; they come in bitfield form of concatenated AG and block numbers
  280.         ; to get absolute block number for fs_read32_sys we should
  281.         ; 1. extract AG number (using precalculated mask)
  282.         ; 2. multiply it by the AG size in blocks
  283.         ; 3. add AG relative block number
  284.  
  285.         ; 1.
  286.         mov     ecx, [ebp + XFS.agblklog]
  287.         shrd    eax, edx, cl
  288.         shr     edx, cl
  289.         ; 2.
  290.         mul     dword[ebp + XFS.agblocks]
  291.         pop     ecx
  292.         pop     esi
  293.         and     ecx, dword[ebp + XFS.agblockmask + 0]
  294.         and     esi, dword[ebp + XFS.agblockmask + 4]
  295.         ; 3.
  296.         add     eax, ecx
  297.         adc     edx, esi
  298.  
  299. ;DEBUGF 1,"read block: 0x%x%x\n",edx,eax
  300.         ; there is no way to read file system block at once, therefore we
  301.         ; 1. calculate the number of sectors first
  302.         ; 2. and then read them in series
  303.  
  304.         ; 1.
  305.         mov     ecx, [ebp + XFS.blockmsectlog]
  306.         shld    edx, eax, cl
  307.         shl     eax, cl
  308.         mov     esi, [ebp + XFS.sectpblock]
  309.  
  310.         ; 2.
  311.   .next_sector:
  312.         push    eax edx
  313.         call    fs_read32_sys
  314.         mov     ecx, eax
  315.         pop     edx eax
  316.         test    ecx, ecx
  317.         jnz     .error
  318.         add     eax, 1                          ; be ready to fs_read64_sys
  319.         adc     edx, 0
  320.         add     ebx, [ebp + XFS.sectsize]       ; update buffer offset
  321.         dec     esi
  322.         jnz     .next_sector
  323.  
  324.   .quit:
  325.         xor     eax, eax
  326.         pop     esi ebx
  327.         ret
  328.   .error:
  329.         mov     eax, ecx
  330.         pop     esi ebx
  331.         ret
  332.  
  333.  
  334. ;---------------------------------------------------------------
  335. ; push buffer
  336. ; push startblock_hi
  337. ; push startblock_lo
  338. ; call xfs_read_dirblock
  339. ; test eax, eax
  340. ;---------------------------------------------------------------
  341. xfs_read_dirblock:
  342. ;mov eax, [esp + 4]
  343. ;mov edx, [esp + 8]
  344. ;DEBUGF 1,"read dirblock at: %d %d\n",edx,eax
  345. ;DEBUGF 1,"dirblklog: %d\n",[ebp + XFS.dirblklog]
  346.         push    ebx esi
  347.  
  348.         mov     eax, [esp + 12]         ; startblock_lo
  349.         mov     edx, [esp + 16]         ; startblock_hi
  350.         mov     ebx, [esp + 20]         ; buffer
  351.  
  352.         ; dirblock >= block
  353.         ; read dirblocks by blocks
  354.  
  355.         mov     ecx, [ebp + XFS.dirblklog]
  356.         mov     esi, 1
  357.         shl     esi, cl
  358.   .next_block:
  359.         push    eax edx
  360.         call    xfs_read_block
  361.         mov     ecx, eax
  362.         pop     edx eax
  363.         test    ecx, ecx
  364.         jnz     .error
  365.         add     eax, 1          ; be ready to fs_read64_sys
  366.         adc     edx, 0
  367.         add     ebx, [ebp + XFS.blocksize]
  368.         dec     esi
  369.         jnz     .next_block
  370.  
  371.   .quit:
  372.         xor     eax, eax
  373.         pop     esi ebx
  374.         ret     12
  375.   .error:
  376.         mov     eax, ecx
  377.         pop     esi ebx
  378.         ret     12
  379.  
  380.  
  381. ;---------------------------------------------------------------
  382. ; push buffer
  383. ; push inode_hi
  384. ; push inode_lo
  385. ; call xfs_read_inode
  386. ; test eax, eax
  387. ;---------------------------------------------------------------
  388. xfs_read_inode:
  389. ;DEBUGF 1,"reading inode: 0x%x%x\n",[esp+8],[esp+4]
  390.         push    ebx
  391.         mov     eax, [esp + 8]  ; inode_lo
  392.         mov     edx, [esp + 12] ; inode_hi
  393.         mov     ebx, [esp + 16] ; buffer
  394.  
  395.         ; inodes are packed into blocks
  396.         ; 1. calculate block number
  397.         ; 2. read the block
  398.         ; 3. add inode offset to block base address
  399.  
  400.         ; 1.
  401.         mov     ecx, [ebp + XFS.inodetoblocklog]
  402.         shrd    eax, edx, cl
  403.         shr     edx, cl
  404.         ; 2.
  405.         call    xfs_read_block
  406.         test    eax, eax
  407.         jnz     .error
  408.  
  409.         ; note that inode numbers should be first extracted from bitfields using mask
  410.  
  411.         mov     eax, [esp + 8]
  412.         mov     edx, 1
  413.         mov     ecx, [ebp + XFS.inopblog]
  414.         shl     edx, cl
  415.         dec     edx             ; get inode number mask
  416.         and     eax, edx        ; apply mask
  417.         mov     ecx, [ebp + XFS.inodelog]
  418.         shl     eax, cl
  419.         add     ebx, eax
  420.  
  421.         cmp     word[ebx], XFS_DINODE_MAGIC     ; test signature
  422.         jne     .error
  423.   .quit:
  424.         xor     eax, eax
  425.         mov     edx, ebx
  426.         pop     ebx
  427.         ret     12
  428.   .error:
  429.         movi    eax, ERROR_FS_FAIL
  430.         mov     edx, ebx
  431.         pop     ebx
  432.         ret     12
  433.  
  434.  
  435. ;----------------------------------------------------------------
  436. ; push encoding         ; ASCII / UNICODE
  437. ; push src              ; inode
  438. ; push dst              ; bdfe
  439. ; push entries_to_read
  440. ; push start_number     ; from 0
  441. ;----------------------------------------------------------------
  442. xfs_dir_get_bdfes:
  443. DEBUGF 1,"xfs_dir_get_bdfes: %d entries from %d\n",[esp+8],[esp+4]
  444.         sub     esp, 4     ; local vars
  445.         push    ecx edx esi edi
  446.  
  447.         mov     ebx, [esp + 36]         ; src
  448.         mov     edx, [esp + 32]         ; dst
  449.         mov     ecx, [esp + 24]         ; start_number
  450.  
  451.         ; define directory ondisk format and jump to corresponding label
  452.  
  453.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL
  454.         jne     .not_shortdir
  455.         jmp     .shortdir
  456.   .not_shortdir:
  457.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  458.         jne     .not_blockdir
  459.         mov     eax, [ebx + xfs_inode.di_core.di_nextents]
  460.         bswap   eax
  461.         cmp     eax, 1
  462.         jne     .not_blockdir
  463.         jmp     .blockdir
  464.   .not_blockdir:
  465.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  466.         jne     .not_leafdir
  467.         mov     eax, [ebx + xfs_inode.di_core.di_nextents]
  468.         bswap   eax
  469.         cmp     eax, 4
  470.         ja      .not_leafdir
  471.         jmp     .leafdir
  472.   .not_leafdir:
  473.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  474.         jne     .not_nodedir
  475.         jmp     .nodedir
  476.   .not_nodedir:
  477.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
  478.         jne     .not_btreedir
  479.         jmp     .btreedir
  480.   .not_btreedir:
  481.         movi    eax, ERROR_FS_FAIL
  482.         jmp     .error
  483.  
  484.         ; short form directory (all the data fits into inode)
  485.   .shortdir:
  486. ;DEBUGF 1,"shortdir\n",
  487.         movzx   eax, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count]
  488.         test    al, al                  ; is count zero?
  489.         jnz     @f                      ; if not, use it (i8count must be zero then)
  490.         shr     eax, 8                  ; use i8count
  491.     @@:
  492.         add     eax, 1                  ; '..' and '.' are implicit
  493.         mov     dword[edx + 0], 1       ; version
  494.         mov     [edx + 8], eax          ; total entries
  495.         sub     eax, [esp + 24]         ; start number
  496.         cmp     eax, [esp + 28]         ; entries to read
  497.         jbe     @f
  498.         mov     eax, [esp + 28]
  499.     @@:
  500.         mov     [esp + 28], eax
  501.         mov     [edx + 4], eax          ; number of actually read entries
  502.         mov     [ebp + XFS.entries_read], eax
  503.  
  504.         ; inode numbers are often saved as 4 bytes (iff they fit)
  505.         ; compute the length of inode numbers
  506.  
  507.         mov     eax, 4          ; 4 by default
  508.         cmp     byte[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.i8count], 0
  509.         je      @f
  510.         add     eax, eax        ; 4+4=8, iff i8count != 0
  511.     @@:
  512.         mov     dword[edx + 12], 0      ; reserved
  513.         mov     dword[edx + 16], 0      ;
  514.         mov     dword[edx + 20], 0      ;
  515.         mov     dword[edx + 24], 0      ;
  516.         mov     dword[edx + 28], 0      ;
  517.         add     edx, 32
  518.         lea     esi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax]
  519.         dec     ecx
  520.         js      .shortdir.fill
  521.  
  522.         ; skip some entries if the first entry to read is not 0
  523.  
  524.   .shortdir.skip:
  525.         test    ecx, ecx
  526.         jz      .shortdir.skipped
  527.         movzx   edi, byte[esi + xfs_dir2_sf_entry.namelen]
  528.         lea     esi, [esi + xfs_dir2_sf_entry.name + edi]
  529.         add     esi, eax
  530.         dec     ecx
  531.         jnz     .shortdir.skip
  532.         mov     ecx, [esp + 28]         ; entries to read
  533.         jmp     .shortdir.skipped
  534.   .shortdir.fill:
  535.         mov     ecx, [esp + 28]         ; total number
  536.         test    ecx, ecx
  537.         jz      .quit
  538.         push    ecx
  539. ;DEBUGF 1,"ecx: %d\n",ecx
  540.         lea     edi, [edx + 40]         ; get file name offset
  541. ;DEBUGF 1,"filename: ..\n"
  542.         mov     dword[edi], '..'
  543.         mov     edi, edx
  544.         push    eax ebx edx esi
  545.         stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent]
  546.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
  547. ;        test    eax, eax
  548. ;        jnz     .error
  549.         stdcall xfs_get_inode_info, edx, edi
  550.         test    eax, eax
  551.         pop     esi edx ebx eax
  552.         jnz     .error
  553.         mov     ecx, [esp + 44]         ; file name encding
  554.         mov     [edx + 4], ecx
  555.         add     edx, 304                ; ASCII only for now
  556.         pop     ecx
  557.         dec     ecx
  558.         jz      .quit
  559.  
  560. ;        push    ecx
  561. ;        lea     edi, [edx + 40]
  562. ;DEBUGF 1,"filename: .\n"
  563. ;        mov     dword[edi], '.'
  564. ;        mov     edi, edx
  565. ;        push    eax edx
  566. ;        stdcall xfs_get_inode_info, [ebp + XFS.cur_inode], edi
  567. ;        test    eax, eax
  568. ;        pop     edx eax
  569. ;        jnz     .error
  570. ;        mov     ecx, [esp + 44]
  571. ;        mov     [edx + 4], ecx
  572. ;        add     edx, 304                ; ASCII only for now
  573. ;        pop     ecx
  574. ;        dec     ecx
  575. ;        jz      .quit
  576.  
  577.         ; we skipped some entries
  578.         ; now we fill min(required, present) number of bdfe's
  579.  
  580.   .shortdir.skipped:
  581. ;DEBUGF 1,"ecx: %d\n",ecx
  582.         push    ecx
  583.         movzx   ecx, byte[esi + xfs_dir2_sf_entry.namelen]
  584.         add     esi, xfs_dir2_sf_entry.name
  585.         lea     edi, [edx + 40]         ; bdfe offset of file name
  586. ;DEBUGF 1,"filename: |%s|\n",esi
  587.         rep movsb
  588.         mov     word[edi], 0            ; terminator (ASCIIZ)
  589.  
  590.         push    eax ebx ecx edx esi
  591. ;        push    edx     ; for xfs_get_inode_info
  592.         mov     edi, edx
  593.         stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [esi + 4], [esi]
  594.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
  595. ;        test    eax, eax
  596. ;        jnz     .error
  597.         stdcall xfs_get_inode_info, edx, edi
  598.         test    eax, eax
  599.         pop     esi edx ecx ebx eax
  600.         jnz     .error
  601.         mov     ecx, [esp + 44]         ; file name encoding
  602.         mov     [edx + 4], ecx
  603.  
  604.         add     edx, 304                ; ASCII only for now
  605.         add     esi, eax
  606.         pop     ecx
  607.         dec     ecx
  608.         jnz     .shortdir.skipped
  609.         jmp     .quit
  610.  
  611.   .blockdir:
  612. ;DEBUGF 1,"blockdir\n"
  613.         push    edx
  614.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  615.         stdcall xfs_extent_unpack, eax
  616. ;DEBUGF 1,"extent.br_startoff  : 0x%x%x\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0]
  617. ;DEBUGF 1,"extent.br_startblock: 0x%x%x\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0]
  618. ;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount]
  619. ;DEBUGF 1,"extent.br_state     : %d\n",[ebp+XFS.extent.br_state]
  620.         stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock]
  621.         test    eax, eax
  622.         pop     edx
  623.         jnz     .error
  624. ;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
  625.         mov     ebx, [ebp + XFS.cur_dirblock]
  626.         mov     dword[edx + 0], 1       ; version
  627.         mov     eax, [ebp + XFS.dirblocksize]
  628.         mov     ecx, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.stale]
  629.         mov     eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count]
  630.         bswap   ecx
  631.         bswap   eax
  632.         sub     eax, ecx                ; actual number of entries = count - stale
  633.         mov     [edx + 8], eax          ; total entries
  634. ;DEBUGF 1,"total entries: %d\n",eax
  635.         sub     eax, [esp + 24]         ; start number
  636.         cmp     eax, [esp + 28]         ; entries to read
  637.         jbe     @f
  638.         mov     eax, [esp + 28]
  639.     @@:
  640.         mov     [esp + 28], eax
  641.         mov     [edx + 4], eax          ; number of actually read entries
  642.         mov     [ebp + XFS.entries_read], eax
  643. ;DEBUGF 1,"actually read entries: %d\n",eax
  644.         mov     dword[edx + 12], 0      ; reserved
  645.         mov     dword[edx + 16], 0      ;
  646.         mov     dword[edx + 20], 0      ;
  647.         mov     dword[edx + 24], 0      ;
  648.         mov     dword[edx + 28], 0      ;
  649.         add     ebx, xfs_dir2_block.u
  650.  
  651.         mov     ecx, [esp + 24]         ; start entry number
  652.                                         ; also means how many to skip
  653.         test    ecx, ecx
  654.         jz      .blockdir.skipped
  655.   .blockdir.skip:
  656.         cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
  657.         jne     @f
  658.         movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
  659.         xchg    al, ah
  660.         add     ebx, eax
  661.         jmp     .blockdir.skip
  662.     @@:
  663.         movzx   eax, [ebx + xfs_dir2_data_union.xentry.namelen]
  664.         lea     ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2]       ; 2 bytes for 'tag'
  665.         add     ebx, 7                  ; align on 8 bytes
  666.         and     ebx, not 7
  667.         dec     ecx
  668.         jnz     .blockdir.skip
  669.   .blockdir.skipped:
  670.         mov     ecx, [edx + 4]          ; actually read entries
  671.         test    ecx, ecx
  672.         jz      .quit
  673.         add     edx, 32                 ; set edx to the first bdfe
  674.   .blockdir.next_entry:
  675.         cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_NULL
  676.         jne     @f
  677.         movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
  678.         xchg    al, ah
  679.         add     ebx, eax
  680.         jmp     .blockdir.next_entry
  681.     @@:
  682.         push    ecx
  683.         push    eax ebx ecx edx esi
  684.         mov     edi, edx
  685.         mov     edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
  686.         mov     eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
  687.         bswap   edx
  688.         bswap   eax
  689.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
  690.         stdcall xfs_get_inode_info, edx, edi
  691.         test    eax, eax
  692.         pop     esi edx ecx ebx eax
  693.         jnz     .error
  694.         mov     ecx, [esp + 44]
  695.         mov     [edx + 4], ecx
  696.         lea     edi, [edx + 40]
  697.         movzx   ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
  698.         lea     esi, [ebx + xfs_dir2_data_union.xentry.name]
  699. ;DEBUGF 1,"filename: |%s|\n",esi
  700.         rep movsb
  701. ;        call    utf8_to_cp866
  702.         mov     word[edi], 0            ; terminator
  703.         lea     ebx, [esi + 2]          ; skip 'tag'
  704.         add     ebx, 7                  ; xfs_dir2_data_entries are aligned to 8 bytes
  705.         and     ebx, not 7
  706.         add     edx, 304
  707.         pop     ecx
  708.         dec     ecx
  709.         jnz     .blockdir.next_entry
  710.         jmp     .quit
  711.  
  712.   .leafdir:
  713. ;DEBUGF 1,"readdir: leaf\n"
  714.         mov     [ebp + XFS.cur_inode_save], ebx
  715.         push    ebx ecx edx
  716.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  717.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  718.         bswap   edx
  719.         stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, 0xffffffff, 0xffffffff
  720.         mov     ecx, eax
  721.         and     ecx, edx
  722.         inc     ecx
  723.         pop     edx ecx ebx
  724.         jz      .error
  725.  
  726.         mov     eax, [ebp + XFS.cur_dirblock]
  727.         movzx   ecx, word[eax + xfs_dir2_leaf.hdr.stale]
  728.         movzx   eax, word[eax + xfs_dir2_leaf.hdr.count]
  729.         xchg    cl, ch
  730.         xchg    al, ah
  731.         sub     eax, ecx
  732. ;DEBUGF 1,"total count: %d\n",eax
  733.  
  734.         mov     dword[edx + 0], 1       ; version
  735.         mov     [edx + 8], eax          ; total entries
  736.         sub     eax, [esp + 24]         ; start number
  737.         cmp     eax, [esp + 28]         ; entries to read
  738.         jbe     @f
  739.         mov     eax, [esp + 28]
  740.     @@:
  741.         mov     [esp + 28], eax
  742.         mov     [edx + 4], eax          ; number of actually read entries
  743.  
  744.         mov     dword[edx + 12], 0      ; reserved
  745.         mov     dword[edx + 16], 0      ;
  746.         mov     dword[edx + 20], 0      ;
  747.         mov     dword[edx + 24], 0      ;
  748.         mov     dword[edx + 28], 0      ;
  749.  
  750.         mov     eax, [ebp + XFS.cur_dirblock]
  751.         add     eax, [ebp + XFS.dirblocksize]
  752.         mov     [ebp + XFS.max_dirblockaddr], eax
  753.         mov     dword[ebp + XFS.next_block_num + 0], 0
  754.         mov     dword[ebp + XFS.next_block_num + 4], 0
  755.  
  756.         mov     ebx, [ebp + XFS.max_dirblockaddr]       ; to read dirblock immediately
  757.         mov     ecx, [esp + 24]         ; start number
  758.         test    ecx, ecx
  759.         jz      .leafdir.skipped
  760.   .leafdir.skip:
  761.         cmp     ebx, [ebp + XFS.max_dirblockaddr]
  762.         jne     @f
  763.         push    ecx edx
  764.         mov     ebx, [ebp + XFS.cur_inode_save]
  765.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  766.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  767.         bswap   edx
  768.         stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  769.         mov     ecx, eax
  770.         and     ecx, edx
  771.         inc     ecx
  772.         jz      .error
  773.         add     eax, 1
  774.         adc     edx, 0
  775.         mov     dword[ebp + XFS.next_block_num + 0], eax
  776.         mov     dword[ebp + XFS.next_block_num + 4], edx
  777.         mov     ebx, [ebp + XFS.cur_dirblock]
  778.         add     ebx, sizeof.xfs_dir2_data_hdr
  779.         pop     edx ecx
  780.     @@:
  781.         cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
  782.         jne     @f
  783.         movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
  784.         xchg    al, ah
  785.         add     ebx, eax
  786.         jmp     .leafdir.skip
  787.     @@:
  788.         movzx   eax, [ebx + xfs_dir2_data_union.xentry.namelen]
  789.         lea     ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2]       ; 2 for 'tag'
  790.         add     ebx, 7
  791.         and     ebx, not 7
  792.         dec     ecx
  793.         jnz     .leafdir.skip
  794.   .leafdir.skipped:
  795.         mov     [ebp + XFS.entries_read], 0
  796.         mov     ecx, [edx + 4]          ; actually read entries
  797.         test    ecx, ecx
  798.         jz      .quit
  799.         add     edx, 32                 ; first bdfe entry
  800.   .leafdir.next_entry:
  801. ;DEBUGF 1,"next_extry\n"
  802.         cmp     ebx, [ebp + XFS.max_dirblockaddr]
  803.         jne     .leafdir.process_current_block
  804.         push    ecx edx
  805.         mov     ebx, [ebp + XFS.cur_inode_save]
  806.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  807.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  808.         bswap   edx
  809.         stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  810. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  811.         mov     ecx, eax
  812.         and     ecx, edx
  813.         inc     ecx
  814.         jnz     @f
  815.         pop     edx ecx
  816.         jmp     .quit
  817.     @@:
  818.         add     eax, 1
  819.         adc     edx, 0
  820.         mov     dword[ebp + XFS.next_block_num + 0], eax
  821.         mov     dword[ebp + XFS.next_block_num + 4], edx
  822.         mov     ebx, [ebp + XFS.cur_dirblock]
  823.         add     ebx, sizeof.xfs_dir2_data_hdr
  824.         pop     edx ecx
  825.   .leafdir.process_current_block:
  826.         cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
  827.         jne     @f
  828.         movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
  829.         xchg    al, ah
  830.         add     ebx, eax
  831.         jmp     .leafdir.next_entry
  832.     @@:
  833.         push    eax ebx ecx edx esi
  834.         mov     edi, edx
  835.         mov     edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
  836.         mov     eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
  837.         bswap   edx
  838.         bswap   eax
  839.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
  840.         stdcall xfs_get_inode_info, edx, edi
  841.         test    eax, eax
  842.         pop     esi edx ecx ebx eax
  843.         jnz     .error
  844.         push    ecx
  845.         mov     ecx, [esp + 44]
  846.         mov     [edx + 4], ecx
  847.         lea     edi, [edx + 40]
  848.         movzx   ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
  849.         lea     esi, [ebx + xfs_dir2_data_union.xentry.name]
  850. ;DEBUGF 1,"filename: |%s|\n",esi
  851.         rep movsb
  852.         pop     ecx
  853.         mov     word[edi], 0
  854.         lea     ebx, [esi + 2]  ; skip 'tag'
  855.         add     ebx, 7          ; xfs_dir2_data_entries are aligned to 8 bytes
  856.         and     ebx, not 7
  857.         add     edx, 304        ; ASCII only for now
  858.         inc     [ebp + XFS.entries_read]
  859.         dec     ecx
  860.         jnz     .leafdir.next_entry
  861.         jmp     .quit
  862.  
  863.   .nodedir:
  864. ;DEBUGF 1,"readdir: node\n"
  865.         push    edx
  866.         mov     [ebp + XFS.cur_inode_save], ebx
  867.         mov     [ebp + XFS.entries_read], 0
  868.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  869.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  870.         bswap   edx
  871.         stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks]
  872.         pop     edx
  873.         test    eax, eax
  874.         jnz     .error
  875.         mov     eax, [ebp + XFS.entries_read]
  876.         mov     [ebp + XFS.entries_read], 0
  877. ;DEBUGF 1,"numfiles: %d\n",eax
  878.         mov     dword[edx + 0], 1       ; version
  879.         mov     [edx + 8], eax          ; total entries
  880.         sub     eax, [esp + 24]         ; start number
  881.         cmp     eax, [esp + 28]         ; entries to read
  882.         jbe     @f
  883.         mov     eax, [esp + 28]
  884.     @@:
  885.         mov     [esp + 28], eax
  886.         mov     [edx + 4], eax          ; number of actually read entries
  887.  
  888.         mov     dword[edx + 12], 0      ; reserved
  889.         mov     dword[edx + 16], 0      ;
  890.         mov     dword[edx + 20], 0      ;
  891.         mov     dword[edx + 24], 0      ;
  892.         mov     dword[edx + 28], 0      ;
  893.  
  894.         mov     eax, [ebp + XFS.cur_dirblock]
  895.         add     eax, [ebp + XFS.dirblocksize]
  896.         mov     [ebp + XFS.max_dirblockaddr], eax
  897.         mov     dword[ebp + XFS.next_block_num + 0], 0
  898.         mov     dword[ebp + XFS.next_block_num + 4], 0
  899.  
  900.         mov     ebx, [ebp + XFS.max_dirblockaddr]       ; to read dirblock immediately
  901.         mov     ecx, [esp + 24]         ; start number
  902.         test    ecx, ecx
  903.         jz      .leafdir.skipped
  904.         jmp     .leafdir.skip
  905.  
  906.   .btreedir:
  907. ;DEBUGF 1,"readdir: btree\n"
  908.         mov     [ebp + XFS.cur_inode_save], ebx
  909.         push    ebx edx
  910.         mov     eax, [ebx + xfs_inode.di_core.di_nextents]
  911.         bswap   eax
  912.         mov     [ebp + XFS.ro_nextents], eax
  913.         mov     eax, [ebp + XFS.inodesize]
  914.         sub     eax, xfs_inode.di_u
  915.         sub     eax, sizeof.xfs_bmdr_block
  916.         shr     eax, 4
  917. ;DEBUGF 1,"maxnumresc: %d\n",eax
  918.         mov     edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0]
  919.         mov     eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4]
  920.         bswap   eax
  921.         bswap   edx
  922.         mov     ebx, [ebp + XFS.cur_block]
  923. ;DEBUGF 1,"read_block: %x %x ",edx,eax
  924.         stdcall xfs_read_block
  925.         pop     edx ebx
  926.         test    eax, eax
  927.         jnz     .error
  928. ;DEBUGF 1,"ok\n"
  929.  
  930.         mov     ebx, [ebp + XFS.cur_block]
  931.         push    edx
  932.         mov     [ebp + XFS.entries_read], 0
  933.         lea     eax, [ebx + sizeof.xfs_bmbt_block]
  934.         mov     edx, [ebp + XFS.ro_nextents]
  935.         stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks]
  936.         pop     edx
  937.         test    eax, eax
  938.         jnz     .error
  939.         mov     eax, [ebp + XFS.entries_read]
  940.         mov     [ebp + XFS.entries_read], 0
  941. ;DEBUGF 1,"numfiles: %d\n",eax
  942.  
  943.         mov     dword[edx + 0], 1       ; version
  944.         mov     [edx + 8], eax          ; total entries
  945.         sub     eax, [esp + 24]         ; start number
  946.         cmp     eax, [esp + 28]         ; entries to read
  947.         jbe     @f
  948.         mov     eax, [esp + 28]
  949.     @@:
  950.         mov     [esp + 28], eax
  951.         mov     [edx + 4], eax          ; number of actually read entries
  952.  
  953.         mov     dword[edx + 12], 0
  954.         mov     dword[edx + 16], 0
  955.         mov     dword[edx + 20], 0
  956.         mov     dword[edx + 24], 0
  957.         mov     dword[edx + 28], 0
  958.  
  959.         mov     eax, [ebp + XFS.cur_dirblock]   ; fsblock?
  960.         add     eax, [ebp + XFS.dirblocksize]
  961.         mov     [ebp + XFS.max_dirblockaddr], eax
  962.         mov     dword[ebp + XFS.next_block_num + 0], 0
  963.         mov     dword[ebp + XFS.next_block_num + 4], 0
  964.  
  965.         mov     ebx, [ebp + XFS.max_dirblockaddr]       ; to read dirblock immediately
  966.         mov     ecx, [esp + 24]         ; start number
  967.         test    ecx, ecx
  968.         jz      .btreedir.skipped
  969. ;        jmp     .btreedir.skip
  970.   .btreedir.skip:
  971.         cmp     ebx, [ebp + XFS.max_dirblockaddr]
  972.         jne     @f
  973.         push    ecx edx
  974.         mov     ebx, [ebp + XFS.cur_block]
  975.         lea     eax, [ebx + sizeof.xfs_bmbt_block]
  976.         mov     edx, [ebp + XFS.ro_nextents]
  977.         stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  978. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  979.         mov     ecx, eax
  980.         and     ecx, edx
  981.         inc     ecx
  982.         jz      .error
  983.         add     eax, 1
  984.         adc     edx, 0
  985.         mov     dword[ebp + XFS.next_block_num + 0], eax
  986.         mov     dword[ebp + XFS.next_block_num + 4], edx
  987.         mov     ebx, [ebp + XFS.cur_dirblock]
  988.         add     ebx, sizeof.xfs_dir2_data_hdr
  989.         pop     edx ecx
  990.     @@:
  991.         cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
  992.         jne     @f
  993.         movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
  994.         xchg    al, ah
  995.         add     ebx, eax
  996.         jmp     .btreedir.skip
  997.     @@:
  998.         movzx   eax, [ebx + xfs_dir2_data_union.xentry.namelen]
  999.         lea     ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2]       ; 2 for 'tag'
  1000.         add     ebx, 7
  1001.         and     ebx, not 7
  1002.         dec     ecx
  1003.         jnz     .btreedir.skip
  1004.   .btreedir.skipped:
  1005.         mov     [ebp + XFS.entries_read], 0
  1006.         mov     ecx, [edx + 4]          ; actually read entries
  1007.         test    ecx, ecx
  1008.         jz      .quit
  1009.         add     edx, 32
  1010.   .btreedir.next_entry:
  1011. ;mov eax, [ebp + XFS.entries_read]
  1012. ;DEBUGF 1,"next_extry: %d\n",eax
  1013.         cmp     ebx, [ebp + XFS.max_dirblockaddr]
  1014.         jne     .btreedir.process_current_block
  1015.         push    ecx edx
  1016.         mov     ebx, [ebp + XFS.cur_block]
  1017.         lea     eax, [ebx + sizeof.xfs_bmbt_block]
  1018.         mov     edx, [ebp + XFS.ro_nextents]
  1019.         stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  1020. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  1021.         mov     ecx, eax
  1022.         and     ecx, edx
  1023.         inc     ecx
  1024.         jnz     @f
  1025.         pop     edx ecx
  1026.         jmp     .quit
  1027.     @@:
  1028.         add     eax, 1
  1029.         adc     edx, 0
  1030.         mov     dword[ebp + XFS.next_block_num + 0], eax
  1031.         mov     dword[ebp + XFS.next_block_num + 4], edx
  1032.         mov     ebx, [ebp + XFS.cur_dirblock]
  1033.         add     ebx, sizeof.xfs_dir2_data_hdr
  1034.         pop     edx ecx
  1035.   .btreedir.process_current_block:
  1036.         cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
  1037.         jne     @f
  1038.         movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
  1039.         xchg    al, ah
  1040.         add     ebx, eax
  1041.         jmp     .btreedir.next_entry
  1042.     @@:
  1043.         push    eax ebx ecx edx esi
  1044.         mov     edi, edx
  1045.         mov     edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
  1046.         mov     eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
  1047.         bswap   edx
  1048.         bswap   eax
  1049.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
  1050.         stdcall xfs_get_inode_info, edx, edi
  1051.         test    eax, eax
  1052.         pop     esi edx ecx ebx eax
  1053.         jnz     .error
  1054.         push    ecx
  1055.         mov     ecx, [esp + 44]
  1056.         mov     [edx + 4], ecx
  1057.         lea     edi, [edx + 40]
  1058.         movzx   ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
  1059.         lea     esi, [ebx + xfs_dir2_data_union.xentry.name]
  1060. ;DEBUGF 1,"filename: |%s|\n",esi
  1061.         rep movsb
  1062.         pop     ecx
  1063.         mov     word[edi], 0
  1064.         lea     ebx, [esi + 2]  ; skip 'tag'
  1065.         add     ebx, 7          ; xfs_dir2_data_entries are aligned to 8 bytes
  1066.         and     ebx, not 7
  1067.         add     edx, 304
  1068.         inc     [ebp + XFS.entries_read]
  1069.         dec     ecx
  1070.         jnz     .btreedir.next_entry
  1071.         jmp     .quit
  1072.  
  1073.  
  1074.   .quit:
  1075.         pop     edi esi edx ecx
  1076.         add     esp, 4  ; pop vars
  1077.         xor     eax, eax
  1078. ;        mov     ebx, [esp + 8]
  1079.         mov     ebx, [ebp + XFS.entries_read]
  1080. DEBUGF 1,"xfs_dir_get_bdfes done: %d\n",ebx
  1081.         ret     20
  1082.   .error:
  1083.         pop     edi esi edx ecx
  1084.         add     esp, 4  ; pop vars
  1085.         mov     eax, ERROR_FS_FAIL
  1086.         movi    ebx, -1
  1087.         ret     20
  1088.  
  1089.  
  1090. ;----------------------------------------------------------------
  1091. ; push inode_hi
  1092. ; push inode_lo
  1093. ; push name
  1094. ;----------------------------------------------------------------
  1095. xfs_get_inode_short:
  1096.         ; this function searches for the file in _current_ dir
  1097.         ; it is called recursively for all the subdirs /path/to/my/file
  1098.  
  1099. ;DEBUGF 1,"xfs_get_inode_short: %s\n",[esp+4]
  1100.         mov     esi, [esp + 4]  ; name
  1101.         movzx   eax, word[esi]
  1102.         cmp     eax, '.'        ; current dir; it is already read, just return
  1103.         je      .quit
  1104.         cmp     eax, './'       ; same thing
  1105.         je      .quit
  1106.  
  1107.         ; read inode
  1108.  
  1109.         mov     eax, [esp + 8]  ; inode_lo
  1110.         mov     edx, [esp + 12] ; inode_hi
  1111.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
  1112.         test    eax, eax
  1113.         movi    eax, ERROR_FS_FAIL
  1114.         jnz     .error
  1115.  
  1116.         ; find file name in directory
  1117.         ; switch directory ondisk format
  1118.  
  1119.         mov     ebx, edx
  1120.         mov     [ebp + XFS.cur_inode_save], ebx
  1121.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL
  1122.         jne     .not_shortdir
  1123. ;DEBUGF 1,"dir: shortdir\n"
  1124.         jmp     .shortdir
  1125.   .not_shortdir:
  1126.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  1127.         jne     .not_blockdir
  1128.         mov     eax, [ebx + xfs_inode.di_core.di_nextents]
  1129.         bswap   eax
  1130.         cmp     eax, 1
  1131.         jne     .not_blockdir
  1132.         jmp     .blockdir
  1133.   .not_blockdir:
  1134.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  1135.         jne     .not_leafdir
  1136.         mov     eax, [ebx + xfs_inode.di_core.di_nextents]
  1137.         bswap   eax
  1138.         cmp     eax, 4
  1139.         ja      .not_leafdir
  1140.         jmp     .leafdir
  1141.   .not_leafdir:
  1142.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  1143.         jne     .not_nodedir
  1144.         jmp     .nodedir
  1145.   .not_nodedir:
  1146.         cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
  1147.         jne     .not_btreedir
  1148.         jmp     .btreedir
  1149.   .not_btreedir:
  1150. DEBUGF 1,"NOT IMPLEMENTED: DIR FORMAT\n"
  1151.         jmp     .error
  1152.  
  1153.   .shortdir:
  1154.   .shortdir.check_parent:
  1155.         ; parent inode number in shortform directories is always implicit, check this case
  1156.         mov     eax, [esi]
  1157.         and     eax, 0x00ffffff
  1158.         cmp     eax, '..'
  1159.         je      .shortdir.parent2
  1160.         cmp     eax, '../'
  1161.         je      .shortdir.parent3
  1162.         jmp     .shortdir.common
  1163.   .shortdir.parent3:
  1164.         inc     esi
  1165.   .shortdir.parent2:
  1166.         add     esi, 2
  1167.         add     ebx, xfs_inode.di_u
  1168.         stdcall xfs_get_inode_number_sf, dword[ebx + xfs_dir2_sf_hdr.count], dword[ebx + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_dir2_sf_hdr.parent]
  1169. ;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
  1170.         jmp     .quit
  1171.  
  1172.         ; not a parent inode?
  1173.         ; search in the list, all the other files are stored uniformly
  1174.  
  1175.   .shortdir.common:
  1176.         mov     eax, 4
  1177.         movzx   edx, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] ; read count (byte) and i8count (byte) at once
  1178.         test    dl, dl          ; is count zero?
  1179.         jnz     @f
  1180.         shr     edx, 8          ; use i8count
  1181.         add     eax, eax        ; inode_num size
  1182.     @@:
  1183.         lea     edi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax]
  1184.  
  1185.   .next_name:
  1186.         movzx   ecx, byte[edi + xfs_dir2_sf_entry.namelen]
  1187.         add     edi, xfs_dir2_sf_entry.name
  1188.         mov     esi, [esp + 4]
  1189. ;DEBUGF 1,"esi: %s\n",esi
  1190. ;DEBUGF 1,"edi: %s\n",edi
  1191.         repe cmpsb
  1192.         jne     @f
  1193.         cmp     byte[esi], 0            ; HINT: use adc here?
  1194.         je      .found
  1195.         cmp     byte[esi], '/'
  1196.         je      .found_inc
  1197.     @@:
  1198.         add     edi, ecx
  1199.         add     edi, eax
  1200.         dec     edx
  1201.         jnz     .next_name
  1202.         movi    eax, ERROR_FILE_NOT_FOUND
  1203.         jmp     .error
  1204.   .found_inc:           ; increment esi to skip '/' symbol
  1205.                         ; this means esi always points to valid file name or zero terminator byte
  1206.         inc     esi
  1207.   .found:
  1208.         stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [edi + 4], [edi]
  1209. ;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
  1210.         jmp     .quit
  1211.  
  1212.   .blockdir:
  1213.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  1214.         stdcall xfs_extent_unpack, eax
  1215.         stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock]
  1216.         test    eax, eax
  1217.         jnz     .error
  1218. ;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
  1219.         mov     ebx, [ebp + XFS.cur_dirblock]
  1220.         mov     eax, [ebp + XFS.dirblocksize]
  1221.         mov     eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count]
  1222.         ; note that we don't subtract xfs_dir2_block_tail.stale here,
  1223.         ; since we need the number of leaf entries rather than file number
  1224.         bswap   eax
  1225.         add     ebx, [ebp + XFS.dirblocksize]
  1226. ;        mov     ecx, sizeof.xfs_dir2_leaf_entry
  1227.         imul    ecx, eax, sizeof.xfs_dir2_leaf_entry
  1228.         sub     ebx, sizeof.xfs_dir2_block_tail
  1229.         sub     ebx, ecx
  1230.         shr     ecx, 3
  1231.         push    ecx     ; for xfs_get_inode_by_hash
  1232.         push    ebx     ; for xfs_get_inode_by_hash
  1233.  
  1234.         mov     edi, esi
  1235.         xor     eax, eax
  1236.         mov     ecx, 4096       ; MAX_PATH_LEN
  1237.         repne scasb
  1238.         movi    eax, ERROR_FS_FAIL
  1239.         jne     .error
  1240.         neg     ecx
  1241.         add     ecx, 4096       ; MAX_PATH_LEN
  1242.         dec     ecx
  1243.         mov     edx, ecx
  1244. ;DEBUGF 1,"strlen total  : %d\n",edx
  1245.         mov     edi, esi
  1246.         mov     eax, '/'
  1247.         mov     ecx, edx
  1248.         repne scasb
  1249.         jne     @f
  1250.         inc     ecx
  1251.     @@:
  1252.         neg     ecx
  1253.         add     ecx, edx
  1254. ;DEBUGF 1,"strlen current: %d\n",ecx
  1255.         stdcall xfs_hashname, esi, ecx
  1256.         add     esi, ecx
  1257.         cmp     byte[esi], '/'
  1258.         jne     @f
  1259.         inc     esi
  1260.     @@:
  1261. ;DEBUGF 1,"hashed: 0x%x\n",eax
  1262. ;        bswap   eax
  1263.         stdcall xfs_get_addr_by_hash
  1264.         bswap   eax
  1265. ;DEBUGF 1,"got address: 0x%x\n",eax
  1266.         cmp     eax, -1
  1267.         jne     @f
  1268.         movi    eax, ERROR_FILE_NOT_FOUND
  1269.         mov     ebx, -1
  1270.         jmp     .error
  1271.     @@:
  1272.         shl     eax, 3
  1273.         mov     ebx, [ebp + XFS.cur_dirblock]
  1274.         add     ebx, eax
  1275.         mov     edx, [ebx + 0]
  1276.         mov     eax, [ebx + 4]
  1277.         bswap   edx
  1278.         bswap   eax
  1279. ;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
  1280.         jmp     .quit
  1281.  
  1282.   .leafdir:
  1283. ;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
  1284.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  1285.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  1286.         bswap   edx
  1287.         stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, -1, -1
  1288. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  1289.         mov     ecx, eax
  1290.         and     ecx, edx
  1291.         inc     ecx
  1292.         jz      .error
  1293.  
  1294.         mov     ebx, [ebp + XFS.cur_dirblock]
  1295.         movzx   eax, [ebx + xfs_dir2_leaf.hdr.count]
  1296.         ; note that we don't subtract xfs_dir2_leaf.hdr.stale here,
  1297.         ; since we need the number of leaf entries rather than file number
  1298.         xchg    al, ah
  1299.         add     ebx, xfs_dir2_leaf.ents
  1300. ;        imul    ecx, eax, sizeof.xfs_dir2_leaf_entry
  1301. ;        shr     ecx, 3
  1302.         push    eax     ; for xfs_get_addr_by_hash: len
  1303.         push    ebx     ; for xfs_get_addr_by_hash: base
  1304.  
  1305.         mov     edi, esi
  1306.         xor     eax, eax
  1307.         mov     ecx, 4096       ; MAX_PATH_LEN
  1308.         repne scasb
  1309.         movi    eax, ERROR_FS_FAIL
  1310.         jne     .error
  1311.         neg     ecx
  1312.         add     ecx, 4096
  1313.         dec     ecx
  1314.         mov     edx, ecx
  1315. ;DEBUGF 1,"strlen total  : %d\n",edx
  1316.         mov     edi, esi
  1317.         mov     eax, '/'
  1318.         mov     ecx, edx
  1319.         repne scasb
  1320.         jne     @f
  1321.         inc     ecx
  1322.     @@:
  1323.         neg     ecx
  1324.         add     ecx, edx
  1325. ;DEBUGF 1,"strlen current: %d\n",ecx
  1326.         stdcall xfs_hashname, esi, ecx
  1327.         add     esi, ecx
  1328.         cmp     byte[esi], '/'
  1329.         jne     @f
  1330.         inc     esi
  1331.     @@:
  1332. ;DEBUGF 1,"hashed: 0x%x\n",eax
  1333.         stdcall xfs_get_addr_by_hash
  1334.         bswap   eax
  1335. ;DEBUGF 1,"got address: 0x%x\n",eax
  1336.         cmp     eax, -1
  1337.         jne     @f
  1338.         movi    eax, ERROR_FILE_NOT_FOUND
  1339.         mov     ebx, -1
  1340.         jmp     .error
  1341.     @@:
  1342.  
  1343.         mov     ebx, [ebp + XFS.cur_inode_save]
  1344.         push    esi edi
  1345.         xor     edi, edi
  1346.         mov     esi, eax
  1347.         shld    edi, esi, 3     ; get offset
  1348.         shl     esi, 3          ; 2^3 = 8 byte align
  1349.         mov     edx, esi
  1350.         mov     ecx, [ebp + XFS.dirblklog]
  1351.         add     ecx, [ebp + XFS.blocklog]
  1352.         mov     eax, 1
  1353.         shl     eax, cl
  1354.         dec     eax
  1355.         and     edx, eax
  1356.         push    edx
  1357.         shrd    esi, edi, cl
  1358.         shr     edi, cl
  1359.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  1360.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  1361.         bswap   edx
  1362.         stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  1363. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  1364.         pop     edx
  1365.         pop     edi esi
  1366.         mov     ecx, eax
  1367.         and     ecx, edx
  1368.         inc     ecx
  1369.         jz      .error
  1370.  
  1371.         mov     ebx, [ebp + XFS.cur_dirblock]
  1372.         add     ebx, edx
  1373.         mov     edx, [ebx + 0]
  1374.         mov     eax, [ebx + 4]
  1375.         bswap   edx
  1376.         bswap   eax
  1377. ;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
  1378.         jmp     .quit
  1379.  
  1380.   .nodedir:
  1381. ;DEBUGF 1,"lookupdir: node\n"
  1382.         mov     [ebp + XFS.cur_inode_save], ebx
  1383.  
  1384.         mov     edi, esi
  1385.         xor     eax, eax
  1386.         mov     ecx, 4096       ; MAX_PATH_LEN
  1387.         repne scasb
  1388.         movi    eax, ERROR_FS_FAIL
  1389.         jne     .error
  1390.         neg     ecx
  1391.         add     ecx, 4096       ; MAX_PATH_LEN
  1392.         dec     ecx
  1393.         mov     edx, ecx
  1394. ;DEBUGF 1,"strlen total  : %d\n",edx
  1395.         mov     edi, esi
  1396.         mov     eax, '/'
  1397.         mov     ecx, edx
  1398.         repne scasb
  1399.         jne     @f
  1400.         inc     ecx
  1401.     @@:
  1402.         neg     ecx
  1403.         add     ecx, edx
  1404. ;DEBUGF 1,"strlen current: %d\n",ecx
  1405.         stdcall xfs_hashname, esi, ecx
  1406.         add     esi, ecx
  1407.         cmp     byte[esi], '/'
  1408.         jne     @f
  1409.         inc     esi
  1410.     @@:
  1411. ;DEBUGF 1,"hashed: 0x%x\n",eax
  1412.         push    edi edx
  1413.         mov     edi, eax
  1414.         mov     [ebp + XFS.entries_read], 0
  1415.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  1416.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  1417.         bswap   edx
  1418.         stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi
  1419.         pop     edx edi
  1420.         test    eax, eax
  1421.         jnz     .error
  1422.         bswap   ecx
  1423. ;DEBUGF 1,"got address: 0x%x\n",ecx
  1424.  
  1425.         mov     ebx, [ebp + XFS.cur_inode_save]
  1426.         push    esi edi
  1427.         xor     edi, edi
  1428.         mov     esi, ecx
  1429.         shld    edi, esi, 3     ; get offset
  1430.         shl     esi, 3          ; 8 byte align
  1431.         mov     edx, esi
  1432.         mov     ecx, [ebp + XFS.dirblklog]
  1433.         add     ecx, [ebp + XFS.blocklog]
  1434.         mov     eax, 1
  1435.         shl     eax, cl
  1436.         dec     eax
  1437.         and     edx, eax
  1438.         push    edx
  1439.         shrd    esi, edi, cl
  1440.         shr     edi, cl
  1441.         lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
  1442.         mov     edx, [ebx + xfs_inode.di_core.di_nextents]
  1443.         bswap   edx
  1444.         stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  1445. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  1446.         pop     edx
  1447.         pop     edi esi
  1448.         mov     ecx, eax
  1449.         and     ecx, edx
  1450.         inc     ecx
  1451.         jz      .error
  1452.  
  1453.         mov     ebx, [ebp + XFS.cur_dirblock]
  1454.         add     ebx, edx
  1455.         mov     edx, [ebx + 0]
  1456.         mov     eax, [ebx + 4]
  1457.         bswap   edx
  1458.         bswap   eax
  1459. ;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
  1460.         jmp     .quit
  1461.  
  1462.   .btreedir:
  1463. DEBUGF 1,"lookupdir: btree\n"
  1464.         mov     [ebp + XFS.cur_inode_save], ebx
  1465.  
  1466.         push    ebx edx
  1467.         mov     eax, [ebx + xfs_inode.di_core.di_nextents]
  1468.         bswap   eax
  1469.         mov     [ebp + XFS.ro_nextents], eax
  1470.         mov     eax, [ebp + XFS.inodesize]
  1471.         sub     eax, xfs_inode.di_u
  1472.         sub     eax, sizeof.xfs_bmdr_block
  1473.         shr     eax, 4  ; FIXME forkoff
  1474. ;DEBUGF 1,"maxnumresc: %d\n",eax
  1475.         mov     edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0]
  1476.         mov     eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4]
  1477.         bswap   eax
  1478.         bswap   edx
  1479.         mov     ebx, [ebp + XFS.cur_block]
  1480. ;DEBUGF 1,"read_block: %x %x ",edx,eax
  1481.         stdcall xfs_read_block
  1482.         pop     edx ebx
  1483.         test    eax, eax
  1484.         jnz     .error
  1485. ;DEBUGF 1,"ok\n"
  1486.         mov     ebx, [ebp + XFS.cur_block]
  1487.  
  1488.         mov     edi, esi
  1489.         xor     eax, eax
  1490.         mov     ecx, 4096       ; MAX_PATH_LEN
  1491.         repne scasb
  1492.         movi    eax, ERROR_FS_FAIL
  1493.         jne     .error
  1494.         neg     ecx
  1495.         add     ecx, 4096
  1496.         dec     ecx
  1497.         mov     edx, ecx
  1498. DEBUGF 1,"strlen total  : %d\n",edx
  1499.         mov     edi, esi
  1500.         mov     eax, '/'
  1501.         mov     ecx, edx
  1502.         repne scasb
  1503.         jne     @f
  1504.         inc     ecx
  1505.     @@:
  1506.         neg     ecx
  1507.         add     ecx, edx
  1508. DEBUGF 1,"strlen current: %d\n",ecx
  1509.         stdcall xfs_hashname, esi, ecx
  1510.         add     esi, ecx
  1511.         cmp     byte[esi], '/'
  1512.         jne     @f
  1513.         inc     esi
  1514.     @@:
  1515. DEBUGF 1,"hashed: 0x%x\n",eax
  1516.         push    edi edx
  1517.         mov     edi, eax
  1518.         mov     [ebp + XFS.entries_read], 0
  1519.         lea     eax, [ebx + sizeof.xfs_bmbt_block]
  1520.         mov     edx, [ebp + XFS.ro_nextents]
  1521. ;push eax
  1522. ;mov eax, [ebp + XFS.dir2_leaf_offset_blocks]
  1523. ;DEBUGF 1,": 0x%x %d\n",eax,eax
  1524. ;pop eax
  1525.         stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi
  1526.         pop     edx edi
  1527.         test    eax, eax
  1528.         jnz     .error
  1529.         bswap   ecx
  1530. DEBUGF 1,"got address: 0x%x\n",ecx
  1531.  
  1532.         mov     ebx, [ebp + XFS.cur_block]
  1533.         push    esi edi
  1534.         xor     edi, edi
  1535.         mov     esi, ecx
  1536.         shld    edi, esi, 3  ; get offset
  1537.         shl     esi, 3
  1538.         mov     edx, esi
  1539.         mov     ecx, [ebp + XFS.dirblklog]
  1540.         add     ecx, [ebp + XFS.blocklog]
  1541.         mov     eax, 1
  1542.         shl     eax, cl
  1543.         dec     eax
  1544.         and     edx, eax
  1545.         push    edx
  1546.         shrd    esi, edi, cl
  1547.         shr     edi, cl
  1548.         lea     eax, [ebx + sizeof.xfs_bmbt_block]
  1549.         mov     edx, [ebp + XFS.ro_nextents]
  1550.         stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
  1551. ;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
  1552.         pop     edx
  1553.         pop     edi esi
  1554.         mov     ecx, eax
  1555.         and     ecx, edx
  1556.         inc     ecx
  1557.         jz      .error
  1558.  
  1559.         mov     ebx, [ebp + XFS.cur_dirblock]
  1560.         add     ebx, edx
  1561.         mov     edx, [ebx + 0]
  1562.         mov     eax, [ebx + 4]
  1563.         bswap   edx
  1564.         bswap   eax
  1565. DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
  1566.         jmp     .quit
  1567.  
  1568.   .quit:
  1569.         ret     12
  1570.   .error:
  1571.         xor     eax, eax
  1572.         mov     edx, eax
  1573.         ret     12
  1574.  
  1575.  
  1576. ;----------------------------------------------------------------
  1577. ; push name
  1578. ; call xfs_get_inode
  1579. ; test eax, eax
  1580. ;----------------------------------------------------------------
  1581. xfs_get_inode:
  1582.         ; call xfs_get_inode_short until file is found / error returned
  1583.  
  1584. ;DEBUGF 1,"getting inode of: %s\n",[esp+4]
  1585.         push    ebx esi edi
  1586.  
  1587.         ; start from the root inode
  1588.  
  1589.         mov     edx, dword[ebp + XFS.rootino + 4]       ; hi
  1590.         mov     eax, dword[ebp + XFS.rootino + 0]       ; lo
  1591.         mov     esi, [esp + 16] ; name
  1592.  
  1593.   .next_dir:
  1594.         cmp     byte[esi], 0
  1595.         je      .found
  1596.  
  1597. ;DEBUGF 1,"next_level: |%s|\n",esi
  1598.         stdcall xfs_get_inode_short, esi, eax, edx
  1599.         test    edx, edx
  1600.         jnz     @f
  1601.         test    eax, eax
  1602.         jz      .error
  1603.     @@:
  1604.         jmp     .next_dir       ; file name found, go to next directory level
  1605.  
  1606.   .found:
  1607.  
  1608.   .quit:
  1609.         pop     edi esi ebx
  1610.         ret     4
  1611.   .error:
  1612.         pop     edi esi ebx
  1613.         xor     eax, eax
  1614.         mov     edx, eax
  1615.         ret     4
  1616.  
  1617.  
  1618. ;----------------------------------------------------------------
  1619. ; xfs_ReadFolder - XFS implementation of reading a folder
  1620. ; in:  ebp = pointer to XFS structure
  1621. ; in:  esi+[esp+4] = name
  1622. ; in:  ebx = pointer to parameters from sysfunc 70
  1623. ; out: eax, ebx = return values for sysfunc 70
  1624. ;----------------------------------------------------------------
  1625. xfs_ReadFolder:
  1626.  
  1627.         ; to read folder
  1628.         ; 1. lock partition
  1629.         ; 2. find inode number
  1630.         ; 3. read this inode
  1631.         ; 4. get bdfe's
  1632.         ; 5. unlock partition
  1633.  
  1634.         ; 1.
  1635.         call    xfs_lock
  1636.         push    ecx edx esi edi
  1637.  
  1638.         ; 2.
  1639.         push    ebx esi edi
  1640.         add     esi, [esp + 32]         ; directory name
  1641. ;DEBUGF 1,"xfs_ReadFolder: |%s|\n",esi
  1642.         stdcall xfs_get_inode, esi
  1643.         pop     edi esi ebx
  1644.         mov     ecx, edx
  1645.         or      ecx, eax
  1646.         jnz     @f
  1647.         movi    eax, ERROR_FILE_NOT_FOUND
  1648.     @@:
  1649.  
  1650.         ; 3.
  1651.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
  1652.         test    eax, eax
  1653.         movi    eax, ERROR_FS_FAIL
  1654.         jnz     .error
  1655.  
  1656.         ; 4.
  1657.         mov     eax, [ebx + 8]          ; encoding
  1658.         and     eax, 1
  1659.         stdcall xfs_dir_get_bdfes, [ebx + 4], [ebx + 12], [ebx + 16], edx, eax
  1660.         test    eax, eax
  1661.         jnz     .error
  1662.  
  1663.   .quit:
  1664. ;DEBUGF 1,"\n\n"
  1665.         pop     edi esi edx ecx
  1666.         ; 5.
  1667.         call    xfs_unlock
  1668.         xor     eax, eax
  1669.         ret
  1670.   .error:
  1671. ;DEBUGF 1,"\n\n"
  1672.         pop     edi esi edx ecx
  1673.         push    eax
  1674.         call    xfs_unlock
  1675.         pop     eax
  1676.         ret
  1677.  
  1678.  
  1679. ;----------------------------------------------------------------
  1680. ; push inode_num_hi
  1681. ; push inode_num_lo
  1682. ; push [count]
  1683. ; call xfs_get_inode_number_sf
  1684. ;----------------------------------------------------------------
  1685. xfs_get_inode_number_sf:
  1686.  
  1687.         ; inode numbers in short form directories may be 4 or 8 bytes long
  1688.         ; determine the length in run time and read inode number at given address
  1689.  
  1690.         cmp     byte[esp + 4 + xfs_dir2_sf_hdr.i8count], 0      ; i8count == 0 means 4 byte per inode number
  1691.         je      .i4bytes
  1692.   .i8bytes:
  1693.         mov     edx, [esp + 12] ; hi
  1694.         mov     eax, [esp + 8]  ; lo
  1695.         bswap   edx             ; big endian
  1696.         bswap   eax
  1697.         ret     12
  1698.   .i4bytes:
  1699.         xor     edx, edx        ; no hi
  1700.         mov     eax, [esp + 12] ; hi = lo
  1701.         bswap   eax             ; big endian
  1702.         ret     12
  1703.  
  1704.  
  1705. ;----------------------------------------------------------------
  1706. ; push dest
  1707. ; push src
  1708. ; call xfs_get_inode_info
  1709. ;----------------------------------------------------------------
  1710. xfs_get_inode_info:
  1711.  
  1712.         ; get access time and other file properties
  1713.         ; useful for browsing directories
  1714.         ; called for each dir entry
  1715.  
  1716. ;DEBUGF 1,"get_inode_info\n"
  1717.         xor     eax, eax
  1718.         mov     edx, [esp + 4]
  1719.         movzx   ecx, word[edx + xfs_inode.di_core.di_mode]
  1720.         xchg    cl, ch
  1721. ;DEBUGF 1,"di_mode: %x\n",ecx
  1722.         test    ecx, S_IFDIR    ; directory?
  1723.         jz      @f
  1724.         mov     eax, 0x10       ; set directory flag
  1725.     @@:
  1726.  
  1727.         mov     edi, [esp + 8]
  1728.         mov     [edi + 0], eax
  1729.         mov     eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
  1730.         bswap   eax
  1731.         mov     dword[edi + 36], eax    ; file size hi
  1732. ;DEBUGF 1,"file_size hi: %d\n",eax
  1733.         mov     eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
  1734.         bswap   eax
  1735.         mov     dword[edi + 32], eax    ; file size lo
  1736. ;DEBUGF 1,"file_size lo: %d\n",eax
  1737.  
  1738.         add     edi, 8
  1739.         mov     eax, [edx + xfs_inode.di_core.di_ctime.t_sec]
  1740.         bswap   eax
  1741.         push    edx
  1742.         xor     edx, edx
  1743.         add     eax, 3054539008                                     ;(369 * 365 + 89) * 24 * 3600
  1744.         adc     edx, 2
  1745.         call    ntfs_datetime_to_bdfe.sec
  1746.         pop     edx
  1747.  
  1748.         mov     eax, [edx + xfs_inode.di_core.di_atime.t_sec]
  1749.         bswap   eax
  1750.         push    edx
  1751.         xor     edx, edx
  1752.         add     eax, 3054539008                                     ;(369 * 365 + 89) * 24 * 3600
  1753.         adc     edx, 2
  1754.         call    ntfs_datetime_to_bdfe.sec
  1755.         pop     edx
  1756.  
  1757.         mov     eax, [edx + xfs_inode.di_core.di_mtime.t_sec]
  1758.         bswap   eax
  1759.         push    edx
  1760.         xor     edx, edx
  1761.         add     eax, 3054539008                                     ;(369 * 365 + 89) * 24 * 3600
  1762.         adc     edx, 2
  1763.         call    ntfs_datetime_to_bdfe.sec
  1764.         pop     edx
  1765.  
  1766.   .quit:
  1767.         xor     eax, eax
  1768.         ret     8
  1769.   .error:
  1770.         movi    eax, ERROR_FS_FAIL
  1771.         ret     8
  1772.  
  1773.  
  1774. ;----------------------------------------------------------------
  1775. ; push extent_data
  1776. ; call xfs_extent_unpack
  1777. ;----------------------------------------------------------------
  1778. xfs_extent_unpack:
  1779.  
  1780.         ; extents come as packet 128bit bitfields
  1781.         ; lets unpack them to access internal fields
  1782.         ; write result to the XFS.extent structure
  1783.  
  1784.         push    eax ebx ecx edx
  1785.         mov     ebx, [esp + 20]
  1786.  
  1787.         xor     eax, eax
  1788.         mov     edx, [ebx + 0]
  1789.         bswap   edx
  1790.         test    edx, 0x80000000         ; mask, see documentation
  1791.         setnz   al
  1792.         mov     [ebp + XFS.extent.br_state], eax
  1793.  
  1794.         and     edx, 0x7fffffff         ; mask
  1795.         mov     eax, [ebx + 4]
  1796.         bswap   eax
  1797.         shrd    eax, edx, 9
  1798.         shr     edx, 9
  1799.         mov     dword[ebp + XFS.extent.br_startoff + 0], eax
  1800.         mov     dword[ebp + XFS.extent.br_startoff + 4], edx
  1801.  
  1802.         mov     edx, [ebx + 4]
  1803.         mov     eax, [ebx + 8]
  1804.         mov     ecx, [ebx + 12]
  1805.         bswap   edx
  1806.         bswap   eax
  1807.         bswap   ecx
  1808.         and     edx, 0x000001ff         ; mask
  1809.         shrd    ecx, eax, 21
  1810.         shrd    eax, edx, 21
  1811.         mov     dword[ebp + XFS.extent.br_startblock + 0], ecx
  1812.         mov     dword[ebp + XFS.extent.br_startblock + 4], eax
  1813.  
  1814.         mov     eax, [ebx + 12]
  1815.         bswap   eax
  1816.         and     eax, 0x001fffff         ; mask
  1817.         mov     [ebp + XFS.extent.br_blockcount], eax
  1818.  
  1819.         pop     edx ecx ebx eax
  1820. ;DEBUGF 1,"extent.br_startoff  : %d %d\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0]
  1821. ;DEBUGF 1,"extent.br_startblock: %d %d\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0]
  1822. ;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount]
  1823. ;DEBUGF 1,"extent.br_state     : %d\n",[ebp+XFS.extent.br_state]
  1824.         ret     4
  1825.  
  1826.  
  1827. ;----------------------------------------------------------------
  1828. ; push namelen
  1829. ; push name
  1830. ; call xfs_hashname
  1831. ;----------------------------------------------------------------
  1832. xfs_hashname:   ; xfs_da_hashname
  1833.  
  1834.         ; simple hash function
  1835.         ; never fails)
  1836.  
  1837.         push    ecx esi
  1838.         xor     eax, eax
  1839.         mov     esi, [esp + 12] ; name
  1840.         mov     ecx, [esp + 16] ; namelen
  1841. ;mov esi, '.'
  1842. ;mov ecx, 1
  1843. ;DEBUGF 1,"hashname: %d %s\n",ecx,esi
  1844.  
  1845.     @@:
  1846.         rol     eax, 7
  1847.         xor     al, [esi]
  1848.         add     esi, 1
  1849.         loop    @b
  1850.  
  1851.         pop     esi ecx
  1852.         ret     8
  1853.  
  1854.  
  1855. ;----------------------------------------------------------------
  1856. ; push  len
  1857. ; push  base
  1858. ; eax -- hash value
  1859. ; call xfs_get_addr_by_hash
  1860. ;----------------------------------------------------------------
  1861. xfs_get_addr_by_hash:
  1862.  
  1863.         ; look for the directory entry offset by its file name hash
  1864.         ; allows fast file search for block, leaf and node directories
  1865.         ; binary (ternary) search
  1866.  
  1867. ;DEBUGF 1,"get_addr_by_hash\n"
  1868.         push    ebx esi
  1869.         mov     ebx, [esp + 12] ; left
  1870.         mov     edx, [esp + 16] ; len
  1871.   .next:
  1872.         mov     ecx, edx
  1873. ;        jecxz   .error
  1874.         test    ecx, ecx
  1875.         jz      .error
  1876.         shr     ecx, 1
  1877.         mov     esi, [ebx + ecx*8 + xfs_dir2_leaf_entry.hashval]
  1878.         bswap   esi
  1879. ;DEBUGF 1,"cmp 0x%x",esi
  1880.         cmp     eax, esi
  1881.         jb      .below
  1882.         ja      .above
  1883.         mov     eax, [ebx + ecx*8 + xfs_dir2_leaf_entry.address]
  1884.         pop     esi ebx
  1885.         ret     8
  1886.   .below:
  1887. ;DEBUGF 1,"b\n"
  1888.         mov     edx, ecx
  1889.         jmp     .next
  1890.   .above:
  1891. ;DEBUGF 1,"a\n"
  1892.         lea     ebx, [ebx + ecx*8 + 8]
  1893.         sub     edx, ecx
  1894.         dec     edx
  1895.         jmp     .next
  1896.   .error:
  1897.         mov     eax, -1
  1898.         pop     esi ebx
  1899.         ret     8
  1900.  
  1901.  
  1902. ;----------------------------------------------------------------
  1903. ; xfs_GetFileInfo - XFS implementation of getting file info
  1904. ; in:  ebp = pointer to XFS structure
  1905. ; in:  esi+[esp+4] = name
  1906. ; in:  ebx = pointer to parameters from sysfunc 70
  1907. ; out: eax, ebx = return values for sysfunc 70
  1908. ;----------------------------------------------------------------
  1909. xfs_GetFileInfo:
  1910.  
  1911.         ; lock partition
  1912.         ; get inode number by file name
  1913.         ; read inode
  1914.         ; get info
  1915.         ; unlock partition
  1916.  
  1917.         push    ecx edx esi edi
  1918.         call    xfs_lock
  1919.  
  1920.         add     esi, [esp + 20]         ; name
  1921. ;DEBUGF 1,"xfs_GetFileInfo: |%s|\n",esi
  1922.         stdcall xfs_get_inode, esi
  1923.         mov     ecx, edx
  1924.         or      ecx, eax
  1925.         jnz     @f
  1926.         movi    eax, ERROR_FILE_NOT_FOUND
  1927.         jmp     .error
  1928.     @@:
  1929.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
  1930.         test    eax, eax
  1931.         movi    eax, ERROR_FS_FAIL
  1932.         jnz     .error
  1933.  
  1934.         stdcall xfs_get_inode_info, edx, [ebx + 16]
  1935.  
  1936.   .quit:
  1937.         call    xfs_unlock
  1938.         pop     edi esi edx ecx
  1939.         xor     eax, eax
  1940. ;DEBUGF 1,"quit\n\n"
  1941.         ret
  1942.   .error:
  1943.         call    xfs_unlock
  1944.         pop     edi esi edx ecx
  1945. ;DEBUGF 1,"error\n\n"
  1946.         ret
  1947.  
  1948.  
  1949. ;----------------------------------------------------------------
  1950. ; xfs_Read - XFS implementation of reading a file
  1951. ; in:  ebp = pointer to XFS structure
  1952. ; in:  esi+[esp+4] = name
  1953. ; in:  ebx = pointer to parameters from sysfunc 70
  1954. ; out: eax, ebx = return values for sysfunc 70
  1955. ;----------------------------------------------------------------
  1956. xfs_Read:
  1957.         push    ebx ecx edx esi edi
  1958.         call    xfs_lock
  1959.  
  1960.         add     esi, [esp + 24]
  1961. ;DEBUGF 1,"xfs_Read: %d %d |%s|\n",[ebx+4],[ebx+12],esi
  1962.         stdcall xfs_get_inode, esi
  1963.         mov     ecx, edx
  1964.         or      ecx, eax
  1965.         jnz     @f
  1966.         movi    eax, ERROR_FILE_NOT_FOUND
  1967.         jmp     .error
  1968.     @@:
  1969.         stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
  1970.         test    eax, eax
  1971.         movi    eax, ERROR_FS_FAIL
  1972.         jnz     .error
  1973.         mov     [ebp + XFS.cur_inode_save], edx
  1974.  
  1975.         cmp     byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
  1976.         jne     .not_extent_list
  1977.         jmp     .extent_list
  1978.   .not_extent_list:
  1979.         cmp     byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
  1980.         jne     .not_btree
  1981.         jmp     .btree
  1982.   .not_btree:
  1983. DEBUGF 1,"XFS: NOT IMPLEMENTED: FILE FORMAT\n"
  1984.         movi    eax, ERROR_FS_FAIL
  1985.         jmp     .error
  1986.   .extent_list:
  1987.         mov     ecx, [ebx + 12]         ; bytes to read
  1988.         mov     edi, [ebx + 16]         ; buffer for data
  1989.         mov     esi, [ebx + 8]          ; offset_hi
  1990.         mov     ebx, [ebx + 4]          ; offset_lo
  1991.  
  1992.         mov     eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
  1993.         bswap   eax
  1994.         mov     dword[ebp + XFS.bytes_left_in_file + 0], eax    ; lo
  1995.         mov     eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
  1996.         bswap   eax
  1997.         mov     dword[ebp + XFS.bytes_left_in_file + 4], eax    ; hi
  1998.  
  1999.         mov     eax, [edx + xfs_inode.di_core.di_nextents]
  2000.         bswap   eax
  2001.         mov     [ebp + XFS.left_extents], eax
  2002.  
  2003.         mov     dword[ebp + XFS.bytes_read], 0          ; actually read bytes
  2004.  
  2005.         xor     eax, eax                ; extent offset in list
  2006.   .extent_list.next_extent:
  2007. ;DEBUGF 1,"extent_list.next_extent, eax: 0x%x\n",eax
  2008. ;DEBUGF 1,"bytes_to_read: %d\n",ecx
  2009. ;DEBUGF 1,"cur file offset: %d %d\n",esi,ebx
  2010. ;DEBUGF 1,"esp: 0x%x\n",esp
  2011.         cmp     [ebp + XFS.left_extents], 0
  2012.         jne     @f
  2013.         test    ecx, ecx
  2014.         jz      .quit
  2015.         movi    eax, ERROR_END_OF_FILE
  2016.         jmp     .error
  2017.     @@:
  2018.         push    eax
  2019.         lea     eax, [edx + xfs_inode.di_u + eax + xfs_bmbt_rec.l0]
  2020.         stdcall xfs_extent_unpack, eax
  2021.         pop     eax
  2022.         dec     [ebp + XFS.left_extents]
  2023.         add     eax, sizeof.xfs_bmbt_rec
  2024.         push    eax ebx ecx edx esi
  2025.         mov     ecx, [ebp + XFS.blocklog]
  2026.         shrd    ebx, esi, cl
  2027.         shr     esi, cl
  2028.         cmp     esi, dword[ebp + XFS.extent.br_startoff + 4]
  2029.         jb      .extent_list.to_hole          ; handle sparse files
  2030.         ja      @f
  2031.         cmp     ebx, dword[ebp + XFS.extent.br_startoff + 0]
  2032.         jb      .extent_list.to_hole          ; handle sparse files
  2033.         je      .extent_list.to_extent        ; read from the start of current extent
  2034.     @@:
  2035.         xor     edx, edx
  2036.         mov     eax, [ebp + XFS.extent.br_blockcount]
  2037.         add     eax, dword[ebp + XFS.extent.br_startoff + 0]
  2038.         adc     edx, dword[ebp + XFS.extent.br_startoff + 4]
  2039. ;DEBUGF 1,"br_startoff: %d %d\n",edx,eax
  2040.         cmp     esi, edx
  2041.         ja      .extent_list.skip_extent
  2042.         jb      .extent_list.to_extent
  2043.         cmp     ebx, eax
  2044.         jae     .extent_list.skip_extent
  2045.         jmp     .extent_list.to_extent
  2046.   .extent_list.to_hole:
  2047. ;DEBUGF 1,"extent_list.to_hole\n"
  2048.         pop     esi edx ecx ebx eax
  2049.         jmp     .extent_list.read_hole
  2050.   .extent_list.to_extent:
  2051. ;DEBUGF 1,"extent_list.to_extent\n"
  2052.         pop     esi edx ecx ebx eax
  2053.         jmp     .extent_list.read_extent
  2054.   .extent_list.skip_extent:
  2055. ;DEBUGF 1,"extent_list.skip_extent\n"
  2056.         pop     esi edx ecx ebx eax
  2057.         jmp     .extent_list.next_extent
  2058.  
  2059.   .extent_list.read_hole:
  2060. ;DEBUGF 1,"hole: offt: 0x%x%x ",esi,ebx
  2061.         push    eax edx
  2062.         mov     eax, dword[ebp + XFS.extent.br_startoff + 0]
  2063.         mov     edx, dword[ebp + XFS.extent.br_startoff + 4]
  2064.         push    esi ebx
  2065.         mov     ebx, ecx
  2066.         sub     eax, ebx        ; get hole_size, it is 64 bit
  2067.         sbb     edx, 0          ; now edx:eax contains the size of hole
  2068. ;DEBUGF 1,"size: 0x%x%x\n",edx,eax
  2069.         jnz     @f              ; if hole size >= 2^32, write bytes_to_read zero bytes
  2070.         cmp     eax, ecx        ; if hole size >= bytes_to_read, write bytes_to_read zeros
  2071.         jae     @f
  2072.         mov     ecx, eax        ; if hole is < than bytes_to_read, write hole size zeros
  2073.     @@:
  2074.         sub     ebx, ecx        ; bytes_to_read - hole_size = left_to_read
  2075.         add     dword[esp + 0], ecx     ; update pushed file offset
  2076.         adc     dword[esp + 4], 0
  2077.         xor     eax, eax        ; hole is made of zeros
  2078.         rep stosb
  2079.         mov     ecx, ebx
  2080.         pop     ebx esi
  2081.  
  2082.         test    ecx, ecx        ; all requested bytes are read?
  2083.         pop     edx eax
  2084.         jz      .quit
  2085.         jmp     .extent_list.read_extent        ; continue from the start of unpacked extent
  2086.  
  2087.   .extent_list.read_extent:
  2088. ;DEBUGF 1,"extent_list.read_extent\n"
  2089.         push    eax ebx ecx edx esi
  2090.         mov     eax, ebx
  2091.         mov     edx, esi
  2092.         mov     ecx, [ebp + XFS.blocklog]
  2093.         shrd    eax, edx, cl
  2094.         shr     edx, cl
  2095.         sub     eax, dword[ebp + XFS.extent.br_startoff + 0]    ; skip esi:ebx ?
  2096.         sbb     edx, dword[ebp + XFS.extent.br_startoff + 4]
  2097.         sub     [ebp + XFS.extent.br_blockcount], eax
  2098.         add     dword[ebp + XFS.extent.br_startblock + 0], eax
  2099.         adc     dword[ebp + XFS.extent.br_startblock + 4], 0
  2100.   .extent_list.read_extent.next_block:
  2101. ;DEBUGF 1,"extent_list.read_extent.next_block\n"
  2102.         cmp     [ebp + XFS.extent.br_blockcount], 0     ; out of blocks in current extent?
  2103.         jne     @f
  2104.         pop     esi edx ecx ebx eax
  2105.         jmp     .extent_list.next_extent                ; go to next extent
  2106.     @@:
  2107.         mov     eax, dword[ebp + XFS.extent.br_startblock + 0]
  2108.         mov     edx, dword[ebp + XFS.extent.br_startblock + 4]
  2109.         push    ebx
  2110.         mov     ebx, [ebp + XFS.cur_block]
  2111. ;DEBUGF 1,"read block: 0x%x%x\n",edx,eax
  2112.         stdcall xfs_read_block
  2113.         test    eax, eax
  2114.         pop     ebx
  2115.         jz      @f
  2116.         pop     esi edx ecx ebx eax
  2117.         movi    eax, ERROR_FS_FAIL
  2118.         jmp     .error
  2119.     @@:
  2120.         dec     [ebp + XFS.extent.br_blockcount]
  2121.         add     dword[ebp + XFS.extent.br_startblock + 0], 1
  2122.         adc     dword[ebp + XFS.extent.br_startblock + 4], 0
  2123.         mov     esi, [ebp + XFS.cur_block]
  2124.         mov     ecx, [ebp + XFS.blocklog]
  2125.         mov     eax, 1
  2126.         shl     eax, cl
  2127.         dec     eax             ; get blocklog mask
  2128.         and     eax, ebx        ; offset in current block
  2129.         add     esi, eax
  2130.         neg     eax
  2131.         add     eax, [ebp + XFS.blocksize]
  2132.         mov     ecx, [esp + 8]  ; pushed ecx, bytes_to_read
  2133.         cmp     ecx, eax        ; is current block enough?
  2134.         jbe     @f              ; if so, read bytes_to_read bytes
  2135.         mov     ecx, eax        ; otherwise read the block up to the end
  2136.     @@:
  2137.         sub     [esp + 8], ecx          ; left_to_read
  2138.         add     [esp + 12], ecx         ; update current file offset, pushed ebx
  2139.         sub     dword[ebp + XFS.bytes_left_in_file + 0], ecx
  2140.         sbb     dword[ebp + XFS.bytes_left_in_file + 4], 0
  2141.         jnc     @f
  2142.         add     dword[ebp + XFS.bytes_left_in_file + 0], ecx
  2143.         mov     ecx, dword[ebp + XFS.bytes_left_in_file + 0]
  2144.         mov     dword[ebp + XFS.bytes_left_in_file + 0], 0
  2145.         mov     dword[ebp + XFS.bytes_left_in_file + 4], 0
  2146.     @@:
  2147.         add     [ebp + XFS.bytes_read], ecx
  2148.         adc     [esp + 0], dword 0      ; pushed esi
  2149. ;DEBUGF 1,"read data: %d\n",ecx
  2150.         rep movsb
  2151.         mov     ecx, [esp + 8]
  2152. ;DEBUGF 1,"left_to_read: %d\n",ecx
  2153.         xor     ebx, ebx
  2154.         test    ecx, ecx
  2155.         jz      @f
  2156.         cmp     dword[ebp + XFS.bytes_left_in_file + 4], 0
  2157.         jne     .extent_list.read_extent.next_block
  2158.         cmp     dword[ebp + XFS.bytes_left_in_file + 0], 0
  2159.         jne     .extent_list.read_extent.next_block
  2160.     @@:
  2161.         pop     esi edx ecx ebx eax
  2162.         jmp     .quit
  2163.  
  2164.   .btree:
  2165.         mov     ecx, [ebx + 12]         ; bytes to read
  2166.         mov     [ebp + XFS.bytes_to_read], ecx
  2167.         mov     edi, [ebx + 16]         ; buffer for data
  2168.         mov     esi, [ebx + 8]          ; offset_hi
  2169.         mov     ebx, [ebx + 4]          ; offset_lo
  2170.         mov     dword[ebp + XFS.file_offset + 0], ebx
  2171.         mov     dword[ebp + XFS.file_offset + 4], esi
  2172.         mov     [ebp + XFS.buffer_pos], edi
  2173.  
  2174.         mov     eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
  2175.         bswap   eax
  2176.         mov     dword[ebp + XFS.bytes_left_in_file + 0], eax    ; lo
  2177.         mov     eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
  2178.         bswap   eax
  2179.         mov     dword[ebp + XFS.bytes_left_in_file + 4], eax    ; hi
  2180.  
  2181.         mov     eax, [edx + xfs_inode.di_core.di_nextents]
  2182.         bswap   eax
  2183.         mov     [ebp + XFS.left_extents], eax
  2184.  
  2185.         mov     dword[ebp + XFS.bytes_read], 0          ; actually read bytes
  2186.  
  2187.         push    ebx ecx edx esi edi
  2188.         mov     [ebp + XFS.eof], 0
  2189.         mov     eax, dword[ebp + XFS.file_offset + 0]
  2190.         mov     edx, dword[ebp + XFS.file_offset + 4]
  2191.         add     eax, [ebp + XFS.bytes_to_read]
  2192.         adc     edx, 0
  2193.         sub     eax, dword[ebp + XFS.bytes_left_in_file + 0]
  2194.         sbb     edx, dword[ebp + XFS.bytes_left_in_file + 4]
  2195.         jc      @f      ; file_offset + bytes_to_read < file_size
  2196.         jz      @f      ; file_offset + bytes_to_read = file_size
  2197.         mov     [ebp + XFS.eof], 1
  2198.         cmp     edx, 0
  2199.         jne     .error.eof
  2200.         sub     dword[ebp + XFS.bytes_to_read], eax
  2201.         jc      .error.eof
  2202.         jz      .error.eof
  2203.     @@:
  2204.         stdcall xfs_btree_read, 0, 0, 1
  2205.         pop     edi esi edx ecx ebx
  2206.         test    eax, eax
  2207.         jnz     .error
  2208.         cmp     [ebp + XFS.eof], 1
  2209.         jne     .quit
  2210.         jmp     .error.eof
  2211.  
  2212.  
  2213.   .quit:
  2214.         call    xfs_unlock
  2215.         pop     edi esi edx ecx ebx
  2216.         xor     eax, eax
  2217.         mov     ebx, [ebp + XFS.bytes_read]
  2218. ;DEBUGF 1,"quit: %d\n\n",ebx
  2219.         ret
  2220.   .error.eof:
  2221.         movi    eax, ERROR_END_OF_FILE
  2222.   .error:
  2223. ;DEBUGF 1,"error\n\n"
  2224.         call    xfs_unlock
  2225.         pop     edi esi edx ecx ebx
  2226.         mov     ebx, [ebp + XFS.bytes_read]
  2227.         ret
  2228.  
  2229.  
  2230. ;----------------------------------------------------------------
  2231. ; push  max_offset_hi
  2232. ; push  max_offset_lo
  2233. ; push  nextents
  2234. ; push  block_number_hi
  2235. ; push  block_number_lo
  2236. ; push  extent_list
  2237. ; -1 / read block number
  2238. ;----------------------------------------------------------------
  2239. xfs_extent_list_read_dirblock:  ; skips holes
  2240. ;DEBUGF 1,"xfs_extent_list_read_dirblock\n"
  2241.         push    ebx esi edi
  2242. ;mov eax, [esp+28]
  2243. ;DEBUGF 1,"nextents: %d\n",eax
  2244. ;mov eax, [esp+20]
  2245. ;mov edx, [esp+24]
  2246. ;DEBUGF 1,"block_number: 0x%x%x\n",edx,eax
  2247. ;mov eax, [esp+32]
  2248. ;mov edx, [esp+36]
  2249. ;DEBUGF 1,"max_addr    : 0x%x%x\n",edx,eax
  2250.         mov     ebx, [esp + 16]
  2251.         mov     esi, [esp + 20]
  2252.         mov     edi, [esp + 24]
  2253. ;        mov     ecx, [esp + 28] ; nextents
  2254.   .next_extent:
  2255. ;DEBUGF 1,"next_extent\n"
  2256.         dec     dword[esp + 28]
  2257.         js      .error
  2258.         stdcall xfs_extent_unpack, ebx
  2259.         add     ebx, sizeof.xfs_bmbt_rec        ; next extent
  2260.         mov     edx, dword[ebp + XFS.extent.br_startoff + 4]
  2261.         mov     eax, dword[ebp + XFS.extent.br_startoff + 0]
  2262.         cmp     edx, [esp + 36] ; max_offset_hi
  2263.         ja      .error
  2264.         jb      @f
  2265.         cmp     eax, [esp + 32] ; max_offset_lo
  2266.         jae     .error
  2267.     @@:
  2268.         cmp     edi, edx
  2269.         jb      .hole
  2270.         ja      .check_count
  2271.         cmp     esi, eax
  2272.         jb      .hole
  2273.         ja      .check_count
  2274.         jmp     .read_block
  2275.   .hole:
  2276. ;DEBUGF 1,"hole\n"
  2277.         mov     esi, eax
  2278.         mov     edi, edx
  2279.         jmp     .read_block
  2280.   .check_count:
  2281. ;DEBUGF 1,"check_count\n"
  2282.         add     eax, [ebp + XFS.extent.br_blockcount]
  2283.         adc     edx, 0
  2284.         cmp     edi, edx
  2285.         ja      .next_extent
  2286.         jb      .read_block
  2287.         cmp     esi, eax
  2288.         jae     .next_extent
  2289. ;        jmp     .read_block
  2290.   .read_block:
  2291. ;DEBUGF 1,"read_block\n"
  2292.         push    esi edi
  2293.         sub     esi, dword[ebp + XFS.extent.br_startoff + 0]
  2294.         sbb     edi, dword[ebp + XFS.extent.br_startoff + 4]
  2295.         add     esi, dword[ebp + XFS.extent.br_startblock + 0]
  2296.         adc     edi, dword[ebp + XFS.extent.br_startblock + 4]
  2297.         stdcall xfs_read_dirblock, esi, edi, [ebp + XFS.cur_dirblock]
  2298.         pop     edx eax
  2299.   .quit:
  2300. ;DEBUGF 1,"xfs_extent_list_read_dirblock: quit\n"
  2301.         pop     edi esi ebx
  2302.         ret     24
  2303.   .error:
  2304. ;DEBUGF 1,"xfs_extent_list_read_dirblock: error\n"
  2305.         xor     eax, eax
  2306.         dec     eax
  2307.         mov     edx, eax
  2308.         pop     edi esi ebx
  2309.         ret     24
  2310.  
  2311.  
  2312. ;----------------------------------------------------------------
  2313. ; push  dirblock_num
  2314. ; push  nextents
  2315. ; push  extent_list
  2316. ;----------------------------------------------------------------
  2317. xfs_dir2_node_get_numfiles:
  2318.  
  2319.         ; unfortunately, we need to set 'total entries' field
  2320.         ; this often requires additional effort, since there is no such a number in most directory ondisk formats
  2321.  
  2322. ;DEBUGF 1,"xfs_dir2_node_get_numfiles\n"
  2323.         push    ebx ecx edx esi edi
  2324.  
  2325.         mov     eax, [esp + 24]
  2326.         mov     edx, [esp + 28]
  2327.         mov     esi, [esp + 32]
  2328.         stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
  2329.         mov     ecx, eax
  2330.         and     ecx, edx
  2331.         inc     ecx
  2332.         jnz     @f
  2333.         movi    eax, ERROR_FS_FAIL
  2334.         jmp     .error
  2335.     @@:
  2336.         mov     ebx, [ebp + XFS.cur_dirblock]
  2337.         cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
  2338.         je      .node
  2339.         cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
  2340.         je      .leaf
  2341.         mov     eax, ERROR_FS_FAIL
  2342.         jmp     .error
  2343.  
  2344.   .node:
  2345. ;DEBUGF 1,".node\n"
  2346.         mov     edi, [ebx + xfs_da_intnode.hdr.info.forw]
  2347.         bswap   edi
  2348.         mov     eax, [esp + 24]
  2349.         mov     edx, [esp + 28]
  2350.         mov     esi, [ebx + xfs_da_intnode.btree.before]
  2351.         bswap   esi
  2352.         stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
  2353.         test    eax, eax
  2354.         jnz     .error
  2355.         jmp     .common
  2356.        
  2357.   .leaf:
  2358. ;DEBUGF 1,".leaf\n"
  2359.         movzx   ecx, word[ebx + xfs_dir2_leaf.hdr.count]
  2360.         xchg    cl, ch
  2361.         movzx   eax, word[ebx + xfs_dir2_leaf.hdr.stale]
  2362.         xchg    al, ah
  2363.         sub     ecx, eax
  2364.         add     [ebp + XFS.entries_read], ecx
  2365.         mov     edi, [ebx + xfs_dir2_leaf.hdr.info.forw]
  2366.         bswap   edi
  2367.         jmp     .common
  2368.  
  2369.   .common:
  2370.         test    edi, edi
  2371.         jz      .quit
  2372.         mov     esi, edi
  2373.         mov     eax, [esp + 24]
  2374.         mov     edx, [esp + 28]
  2375.         stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
  2376.         test    eax, eax
  2377.         jnz     .error
  2378.         jmp     .quit
  2379.  
  2380.   .quit:
  2381. ;DEBUGF 1,".quit\n"
  2382.         pop     edi esi edx ecx ebx
  2383.         xor     eax, eax
  2384.         ret     12
  2385.   .error:
  2386. ;DEBUGF 1,".error\n"
  2387.         pop     edi esi edx ecx ebx
  2388.         movi    eax, ERROR_FS_FAIL
  2389.         ret     12
  2390.  
  2391.  
  2392. ;----------------------------------------------------------------
  2393. ; push  hash
  2394. ; push  dirblock_num
  2395. ; push  nextents
  2396. ; push  extent_list
  2397. ;----------------------------------------------------------------
  2398. xfs_dir2_lookupdir_node:
  2399. DEBUGF 1,"xfs_dir2_lookupdir_node\n"
  2400.         push    ebx edx esi edi
  2401.  
  2402.         mov     eax, [esp + 20]
  2403.         mov     edx, [esp + 24]
  2404.         mov     esi, [esp + 28]
  2405. DEBUGF 1,"read dirblock: 0x%x %d\n",esi,esi
  2406.         stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
  2407. DEBUGF 1,"dirblock read: 0x%x%x\n",edx,eax
  2408.         mov     ecx, eax
  2409.         and     ecx, edx
  2410.         inc     ecx
  2411.         jnz     @f
  2412.         movi    eax, ERROR_FS_FAIL
  2413.         jmp     .error
  2414.     @@:
  2415. DEBUGF 1,"checkpoint #1\n"
  2416.         mov     ebx, [ebp + XFS.cur_dirblock]
  2417.         cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
  2418.         je      .node
  2419.         cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
  2420.         je      .leaf
  2421.         mov     eax, ERROR_FS_FAIL
  2422. DEBUGF 1,"checkpoint #2\n"
  2423.         jmp     .error
  2424.  
  2425.   .node:
  2426. DEBUGF 1,".node\n"
  2427.         mov     edi, [esp + 32] ; hash
  2428.         movzx   ecx, word[ebx + xfs_da_intnode.hdr.count]
  2429.         xchg    cl, ch
  2430.         mov     [ebp + XFS.left_leaves], ecx
  2431.         xor     ecx, ecx
  2432.   .node.next_leaf:
  2433.         mov     esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.hashval]
  2434.         bswap   esi
  2435.         cmp     edi, esi
  2436.         jbe     .node.leaf_found
  2437.         inc     ecx
  2438.         cmp     ecx, [ebp + XFS.left_leaves]
  2439.         jne     .node.next_leaf
  2440.         mov     eax, ERROR_FILE_NOT_FOUND
  2441.         jmp     .error
  2442.     @@:
  2443.   .node.leaf_found:
  2444.         mov     eax, [esp + 20]
  2445.         mov     edx, [esp + 24]
  2446.         mov     esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.before]
  2447.         bswap   esi
  2448.         stdcall xfs_dir2_lookupdir_node, eax, edx, esi, edi
  2449.         test    eax, eax
  2450.         jz      .quit
  2451.         movi    eax, ERROR_FILE_NOT_FOUND
  2452.         jmp     .error
  2453.  
  2454.   .leaf:
  2455. DEBUGF 1,".leaf\n"
  2456.         movzx   ecx, [ebx + xfs_dir2_leaf.hdr.count]
  2457.         xchg    cl, ch
  2458.         lea     esi, [ebx + xfs_dir2_leaf.ents]
  2459.         mov     eax, [esp + 32]
  2460.         stdcall xfs_get_addr_by_hash, esi, ecx
  2461.         cmp     eax, -1
  2462.         je      .error
  2463.         mov     ecx, eax
  2464.         jmp     .quit
  2465.  
  2466.   .quit:
  2467. DEBUGF 1,".quit\n"
  2468.         pop     edi esi edx ebx
  2469.         xor     eax, eax
  2470.         ret     16
  2471.   .error:
  2472. DEBUGF 1,".error\n"
  2473.         pop     edi esi edx ebx
  2474.         ret     16
  2475.  
  2476.  
  2477. ;----------------------------------------------------------------
  2478. ; push  dirblock_num
  2479. ; push  nextents
  2480. ; push  extent_list
  2481. ;----------------------------------------------------------------
  2482. xfs_dir2_btree_get_numfiles:
  2483. ;DEBUGF 1,"xfs_dir2_node_get_numfiles\n"
  2484.         push    ebx ecx edx esi edi
  2485.  
  2486.         mov     eax, [esp + 24]
  2487.         mov     edx, [esp + 28]
  2488.         mov     esi, [esp + 32]
  2489.         stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
  2490.         mov     ecx, eax
  2491.         and     ecx, edx
  2492.         inc     ecx
  2493.         jnz     @f
  2494.         movi    eax, ERROR_FS_FAIL
  2495.         jmp     .error
  2496.     @@:
  2497.         mov     ebx, [ebp + XFS.cur_dirblock]
  2498.         cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
  2499.         je      .node
  2500.         cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
  2501.         je      .leaf
  2502.         mov     eax, ERROR_FS_FAIL
  2503.         jmp     .error
  2504.  
  2505.   .node:
  2506. ;DEBUGF 1,".node\n"
  2507.         mov     edi, [ebx + xfs_da_intnode.hdr.info.forw]
  2508.         bswap   edi
  2509.         mov     eax, [esp + 24]
  2510.         mov     edx, [esp + 28]
  2511.         mov     esi, [ebx + xfs_da_intnode.btree.before]
  2512.         bswap   esi
  2513.         stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
  2514.         test    eax, eax
  2515.         jnz     .error
  2516.         jmp     .common
  2517.        
  2518.   .leaf:
  2519. ;DEBUGF 1,".leaf\n"
  2520.         movzx   ecx, word[ebx + xfs_dir2_leaf.hdr.count]
  2521.         xchg    cl, ch
  2522.         movzx   eax, word[ebx + xfs_dir2_leaf.hdr.stale]
  2523.         xchg    al, ah
  2524.         sub     ecx, eax
  2525.         add     [ebp + XFS.entries_read], ecx
  2526.         mov     edi, [ebx + xfs_dir2_leaf.hdr.info.forw]
  2527.         bswap   edi
  2528.         jmp     .common
  2529.  
  2530.   .common:
  2531.         test    edi, edi
  2532.         jz      .quit
  2533.         mov     esi, edi
  2534.         mov     eax, [esp + 24]
  2535.         mov     edx, [esp + 28]
  2536.         stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
  2537.         test    eax, eax
  2538.         jnz     .error
  2539.         jmp     .quit
  2540.  
  2541.   .quit:
  2542. ;DEBUGF 1,".quit\n"
  2543.         pop     edi esi edx ecx ebx
  2544.         xor     eax, eax
  2545.         ret     12
  2546.   .error:
  2547. ;DEBUGF 1,".error\n"
  2548.         pop     edi esi edx ecx ebx
  2549.         movi    eax, ERROR_FS_FAIL
  2550.         ret     12
  2551.  
  2552.  
  2553. ;----------------------------------------------------------------
  2554. ; push  is_root
  2555. ; push  block_hi
  2556. ; push  block_lo
  2557. ;----------------------------------------------------------------
  2558. xfs_btree_read:
  2559.         push    ebx ecx edx esi edi
  2560.         cmp     dword[esp + 32], 1      ; is root?
  2561.         je      .root
  2562.         jmp     .not_root
  2563.   .root:
  2564. DEBUGF 1,".root\n"
  2565.         mov     ebx, [ebp + XFS.cur_inode_save]
  2566.         add     ebx, xfs_inode.di_u
  2567.         movzx   edx, [ebx + xfs_bmdr_block.bb_numrecs]
  2568.         xchg    dl, dh
  2569.         dec     edx
  2570.         add     ebx, sizeof.xfs_bmdr_block
  2571.         xor     eax, eax
  2572.         dec     eax
  2573.  .root.next_key:
  2574. DEBUGF 1,".root.next_key\n"
  2575.         cmp     [ebp + XFS.bytes_to_read], 0
  2576.         je      .quit
  2577.         inc     eax
  2578.         cmp     eax, edx        ; out of keys?
  2579.         ja      .root.key_found ; there is no length field, so try the last key
  2580.         lea     edi, [ebx + sizeof.xfs_bmbt_key*eax + 0]
  2581.         lea     esi, [ebx + sizeof.xfs_bmbt_key*eax + 4]
  2582.         bswap   edi
  2583.         bswap   esi
  2584.         mov     ecx, [ebp + XFS.blocklog]
  2585.         shld    edi, esi, cl
  2586.         shl     esi, cl
  2587.         cmp     edi, dword[ebp + XFS.file_offset + 4]
  2588.         ja      .root.prev_or_hole
  2589.         jb      .root.next_key
  2590.         cmp     esi, dword[ebp + XFS.file_offset + 0]
  2591.         ja      .root.prev_or_hole
  2592.         jb      .root.next_key
  2593.         jmp     .root.key_found
  2594.   .root.prev_or_hole:
  2595. DEBUGF 1,".root.prev_or_hole\n"
  2596.         test    eax, eax
  2597.         jz      .root.hole
  2598.         dec     eax
  2599.         jmp     .root.key_found
  2600.   .root.hole:
  2601. DEBUGF 1,".root.hole\n"
  2602.         push    eax edx esi edi
  2603.         mov     ecx, [ebp + XFS.blocklog]
  2604.         shld    edi, esi, cl
  2605.         shl     esi, cl
  2606.         sub     esi, dword[ebp + XFS.file_offset + 0]
  2607.         sbb     edi, dword[ebp + XFS.file_offset + 4]
  2608.         mov     ecx, [ebp + XFS.bytes_to_read]
  2609.         cmp     edi, 0  ; hole size >= 2^32
  2610.         jne     @f
  2611.         cmp     ecx, esi
  2612.         jbe     @f
  2613.         mov     ecx, esi
  2614.     @@:
  2615.         add     dword[ebp + XFS.file_offset + 0], ecx
  2616.         adc     dword[ebp + XFS.file_offset + 4], 0
  2617.         sub     [ebp + XFS.bytes_to_read], ecx
  2618.         xor     eax, eax
  2619.         mov     edi, [ebp + XFS.buffer_pos]
  2620.         rep stosb
  2621.         mov     [ebp + XFS.buffer_pos], edi
  2622.         pop     edi esi edx eax
  2623.         jmp     .root.next_key
  2624.   .root.key_found:
  2625. DEBUGF 1,".root.key_found\n"
  2626.         mov     edx, [ebp + XFS.cur_inode_save]
  2627.         mov     eax, [ebp + XFS.inodesize]
  2628.         sub     eax, xfs_inode.di_u
  2629.         cmp     [edx + xfs_inode.di_core.di_forkoff], 0
  2630.         je      @f
  2631.         movzx   eax, [edx + xfs_inode.di_core.di_forkoff]
  2632.         shl     eax, XFS_DIR2_DATA_ALIGN_LOG    ; 3
  2633.     @@:
  2634.         sub     eax, sizeof.xfs_bmdr_block
  2635.         shr     eax, 4  ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr)
  2636.         mov     edx, [ebx + sizeof.xfs_bmbt_key*eax + 0]        ; hi
  2637.         mov     eax, [ebx + sizeof.xfs_bmbt_key*eax + 4]        ; hi
  2638.         bswap   edx
  2639.         bswap   eax
  2640.         stdcall xfs_btree_read, eax, edx, 0
  2641.         test    eax, eax
  2642.         jnz     .error
  2643.         jmp     .root.next_key
  2644.  
  2645.   .not_root:
  2646. DEBUGF 1,".root.not_root\n"
  2647.         mov     eax, [esp + 24] ; block_lo
  2648.         mov     edx, [esp + 28] ; block_hi
  2649.         mov     ebx, [ebp + XFS.cur_block]
  2650.         stdcall xfs_read_block
  2651.         test    eax, eax
  2652.         jnz     .error
  2653.         mov     ebx, [ebp + XFS.cur_block]
  2654.  
  2655.         cmp     [ebx + xfs_bmbt_block.bb_magic], XFS_BMAP_MAGIC
  2656.         jne     .error
  2657.         cmp     [ebx + xfs_bmbt_block.bb_level], 0      ; leaf?
  2658.         je      .leaf
  2659.         jmp     .node
  2660.  
  2661.   .node:
  2662. ;        mov     eax, [ebp + XFS.blocksize]
  2663. ;        sub     eax, sizeof.xfs_bmbt_block
  2664. ;        shr     eax, 4  ; maxnumrecs
  2665.         mov     eax, dword[ebp + XFS.file_offset + 0]   ; lo
  2666.         mov     edx, dword[ebp + XFS.file_offset + 4]   ; hi
  2667.         movzx   edx, [ebx + xfs_bmbt_block.bb_numrecs]
  2668.         xchg    dl, dh
  2669.         dec     edx
  2670.         add     ebx, sizeof.xfs_bmbt_block
  2671.         xor     eax, eax
  2672.         dec     eax
  2673.   .node.next_key:
  2674.         push    eax ecx edx esi edi
  2675.         mov     eax, [esp + 44] ; block_lo
  2676.         mov     edx, [esp + 48] ; block_hi
  2677.         mov     ebx, [ebp + XFS.cur_block]
  2678.         stdcall xfs_read_block
  2679.         test    eax, eax
  2680.         jnz     .error
  2681.         mov     ebx, [ebp + XFS.cur_block]
  2682.         add     ebx, sizeof.xfs_bmbt_block
  2683.         pop     edi esi edx ecx eax
  2684.         cmp     [ebp + XFS.bytes_to_read], 0
  2685.         je      .quit
  2686.         inc     eax
  2687.         cmp     eax, edx        ; out of keys?
  2688.         ja      .node.key_found ; there is no length field, so try the last key
  2689.         lea     edi, [ebx + sizeof.xfs_bmbt_key*eax + 0]
  2690.         lea     esi, [ebx + sizeof.xfs_bmbt_key*eax + 4]
  2691.         bswap   edi
  2692.         bswap   esi
  2693.         mov     ecx, [ebp + XFS.blocklog]
  2694.         shld    edi, esi, cl
  2695.         shl     esi, cl
  2696.         cmp     edi, dword[ebp + XFS.file_offset + 4]
  2697.         ja      .node.prev_or_hole
  2698.         jb      .node.next_key
  2699.         cmp     esi, dword[ebp + XFS.file_offset + 0]
  2700.         ja      .node.prev_or_hole
  2701.         jb      .node.next_key
  2702.         jmp     .node.key_found
  2703.   .node.prev_or_hole:
  2704.         test    eax, eax
  2705.         jz      .node.hole
  2706.         dec     eax
  2707.         jmp     .node.key_found
  2708.   .node.hole:
  2709.         push    eax edx esi edi
  2710.         mov     ecx, [ebp + XFS.blocklog]
  2711.         shld    edi, esi, cl
  2712.         shl     esi, cl
  2713.         sub     esi, dword[ebp + XFS.file_offset + 0]
  2714.         sbb     edi, dword[ebp + XFS.file_offset + 4]
  2715.         mov     ecx, [ebp + XFS.bytes_to_read]
  2716.         cmp     edi, 0  ; hole size >= 2^32
  2717.         jne     @f
  2718.         cmp     ecx, esi
  2719.         jbe     @f
  2720.         mov     ecx, esi
  2721.     @@:
  2722.         add     dword[ebp + XFS.file_offset + 0], ecx
  2723.         adc     dword[ebp + XFS.file_offset + 4], 0
  2724.         sub     [ebp + XFS.bytes_to_read], ecx
  2725.         xor     eax, eax
  2726.         mov     edi, [ebp + XFS.buffer_pos]
  2727.         rep stosb
  2728.         mov     [ebp + XFS.buffer_pos], edi
  2729.         pop     edi esi edx eax
  2730.         jmp     .node.next_key
  2731.   .node.key_found:
  2732.         mov     edx, [ebp + XFS.cur_inode_save]
  2733.         mov     eax, [ebp + XFS.inodesize]
  2734.         sub     eax, xfs_inode.di_u
  2735.         cmp     [edx + xfs_inode.di_core.di_forkoff], 0
  2736.         je      @f
  2737.         movzx   eax, [edx + xfs_inode.di_core.di_forkoff]
  2738.         shl     eax, XFS_DIR2_DATA_ALIGN_LOG    ; 3
  2739.     @@:
  2740.         sub     eax, sizeof.xfs_bmdr_block
  2741.         shr     eax, 4  ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr)
  2742.         mov     edx, [ebx + sizeof.xfs_bmbt_key*eax + 0]        ; hi
  2743.         mov     eax, [ebx + sizeof.xfs_bmbt_key*eax + 4]        ; hi
  2744.         bswap   edx
  2745.         bswap   eax
  2746.         stdcall xfs_btree_read, eax, edx, 0
  2747.         test    eax, eax
  2748.         jnz     .error
  2749.         jmp     .node.next_key
  2750.         jmp     .quit
  2751.  
  2752.   .leaf:
  2753.        
  2754.         jmp     .quit
  2755.  
  2756.   .error:
  2757.         pop     edi esi edx ecx ebx
  2758.         movi    eax, ERROR_FS_FAIL
  2759.         ret     4
  2760.   .quit:
  2761.         pop     edi esi edx ecx ebx
  2762.         xor     eax, eax
  2763.         ret     4
  2764.  
  2765.  
  2766. ;----------------------------------------------------------------
  2767. ; push  nextents
  2768. ; push  extent_list
  2769. ; push  file_offset_hi
  2770. ; push  file_offset_lo
  2771. ;----------------------------------------------------------------
  2772. ;xfs_extent_list_read:
  2773. ;        push    ebx 0 edx esi edi       ; zero means actually_read_bytes
  2774. ;
  2775. ;  .quit:
  2776. ;        pop     edi esi edx ecx ebx
  2777. ;        xor     eax, eax
  2778. ;        ret     24
  2779. ;  .error:
  2780. ;        pop     edi esi edx ecx ebx
  2781. ;        ret     24
  2782.