Subversion Repositories Kolibri OS

Rev

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

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