;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2013-2014. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision$


; from stat.h
; distinguish file types
S_IFMT      = 0170000o  ; These bits determine file type.
S_IFDIR     = 0040000o  ; Directory.
S_IFCHR     = 0020000o  ; Character device.
S_IFBLK     = 0060000o  ; Block device.
S_IFREG     = 0100000o  ; Regular file.
S_IFIFO     = 0010000o  ; FIFO.
S_IFLNK     = 0120000o  ; Symbolic link.
S_IFSOCK    = 0140000o  ; Socket.
; end stat.h


; XFS null constant: empty fields must be all ones, not zeros!
XFS_NULL                = -1


; static sector numbers
XFS_SECT_SB             = 0
XFS_SECT_AGF            = 1
XFS_SECT_AGI            = 2
XFS_SECT_AGFL           = 3


; signatures of file system structures
; 'string' numbers are treated by fasm as big endian
XFS_SB_MAGIC            = 'XFSB'
XFS_AGF_MAGIC           = 'XAGF'
XFS_AGI_MAGIC           = 'XAGI'
XFS_ABTB_MAGIC          = 'ABTB'
XFS_ABTC_MAGIC          = 'ABTC'
XFS_IBT_MAGIC           = 'IABT'
XFS_DINODE_MAGIC        = 'IN'
XFS_BMAP_MAGIC          = 'BMAP'
XFS_DA_NODE_MAGIC       = 0xbefe        ; those are little endian here
XFS_ATTR_LEAF_MAGIC     = 0xeefb        ; but big endian in docs
XFS_DIR2_LEAF1_MAGIC    = 0xf1d2        ; pay attention!
XFS_DIR2_LEAFN_MAGIC    = 0xffd2        ;
XFS_DIR2_BLOCK_MAGIC    = 'XD2B'
XFS_DIR2_DATA_MAGIC     = 'XD2D'
XFS_DIR2_FREE_MAGIC     = 'XD2F'
XFS_DQUOT_MAGIC         = 'DQ'


; bitfield lengths for packed extent
; MSB to LSB / left to right
BMBT_EXNTFLAG_BITLEN    =  1
BMBT_STARTOFF_BITLEN    = 54
BMBT_STARTBLOCK_BITLEN  = 52
BMBT_BLOCKCOUNT_BITLEN  = 21


; those constants are taken from linux source (xfs_dir2_leaf.h)
; they are magic infile offsets for directories
XFS_DIR2_DATA_ALIGN_LOG = 3     ; i.e., 8 bytes
XFS_DIR2_LEAF_SPACE     = 1
XFS_DIR2_SPACE_SIZE     = (1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG))
XFS_DIR2_LEAF_OFFSET    = (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
XFS_DIR2_FREE_SPACE     = 2
XFS_DIR2_SPACE_SIZE     = (1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG))
XFS_DIR2_FREE_OFFSET    = (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE)


; data section magic constants for directories (xfs_dir2_data.h)
XFS_DIR2_DATA_FD_COUNT  = 3
XFS_DIR2_DATA_FREE_TAG  = 0xffff


; valid inode formats
; enum xfs_dinode_fmt (xfs_dinode.h)
XFS_DINODE_FMT_DEV      = 0     ; xfs_dev_t
XFS_DINODE_FMT_LOCAL    = 1     ; one inode is enough (shortdir)
XFS_DINODE_FMT_EXTENTS  = 2     ; one or more extents (leafdir, nodedir, regular files)
XFS_DINODE_FMT_BTREE    = 3     ; highly fragmented files or really huge directories
XFS_DINODE_FMT_UUID     = 4     ; uuid_t


; size of the unlinked inode hash table in the agi
XFS_AGI_UNLINKED_BUCKETS = 64


; possible extent states
; enum xfs_exntst_t (xfs_bmap_btree.h)
XFS_EXT_NORM            = 0
XFS_EXT_UNWRITTEN       = 1
XFS_EXT_DMAPI_OFFLINE   = 2
XFS_EXT_INVALID         = 3


; values for inode core flags / di_flags (xfs_dinode.h)
XFS_DIFLAG_REALTIME_BIT     =  0        ; file's blocks come from rt area
XFS_DIFLAG_PREALLOC_BIT     =  1        ; file space has been preallocated
XFS_DIFLAG_NEWRTBM_BIT      =  2        ; for rtbitmap inode, new format
XFS_DIFLAG_IMMUTABLE_BIT    =  3        ; inode is immutable
XFS_DIFLAG_APPEND_BIT       =  4        ; inode is append-only
XFS_DIFLAG_SYNC_BIT         =  5        ; inode is written synchronously
XFS_DIFLAG_NOATIME_BIT      =  6        ; do not update atime
XFS_DIFLAG_NODUMP_BIT       =  7        ; do not dump
XFS_DIFLAG_RTINHERIT_BIT    =  8        ; create with realtime bit set
XFS_DIFLAG_PROJINHERIT_BIT  =  9        ; create with parents projid
XFS_DIFLAG_NOSYMLINKS_BIT   = 10        ; disallow symlink creation
XFS_DIFLAG_EXTSIZE_BIT      = 11        ; inode extent size allocator hint
XFS_DIFLAG_EXTSZINHERIT_BIT = 12        ; inherit inode extent size
XFS_DIFLAG_NODEFRAG_BIT     = 13        ; do not reorganize/defragment
XFS_DIFLAG_FILESTREAM_BIT   = 14        ; use filestream allocator
XFS_DIFLAG_REALTIME         = (1 SHL XFS_DIFLAG_REALTIME_BIT)
XFS_DIFLAG_PREALLOC         = (1 SHL XFS_DIFLAG_PREALLOC_BIT)
XFS_DIFLAG_NEWRTBM          = (1 SHL XFS_DIFLAG_NEWRTBM_BIT)
XFS_DIFLAG_IMMUTABLE        = (1 SHL XFS_DIFLAG_IMMUTABLE_BIT)
XFS_DIFLAG_APPEND           = (1 SHL XFS_DIFLAG_APPEND_BIT)
XFS_DIFLAG_SYNC             = (1 SHL XFS_DIFLAG_SYNC_BIT)
XFS_DIFLAG_NOATIME          = (1 SHL XFS_DIFLAG_NOATIME_BIT)
XFS_DIFLAG_NODUMP           = (1 SHL XFS_DIFLAG_NODUMP_BIT)
XFS_DIFLAG_RTINHERIT        = (1 SHL XFS_DIFLAG_RTINHERIT_BIT)
XFS_DIFLAG_PROJINHERIT      = (1 SHL XFS_DIFLAG_PROJINHERIT_BIT)
XFS_DIFLAG_NOSYMLINKS       = (1 SHL XFS_DIFLAG_NOSYMLINKS_BIT)
XFS_DIFLAG_EXTSIZE          = (1 SHL XFS_DIFLAG_EXTSIZE_BIT)
XFS_DIFLAG_EXTSZINHERIT     = (1 SHL XFS_DIFLAG_EXTSZINHERIT_BIT)
XFS_DIFLAG_NODEFRAG         = (1 SHL XFS_DIFLAG_NODEFRAG_BIT)
XFS_DIFLAG_FILESTREAM       = (1 SHL XFS_DIFLAG_FILESTREAM_BIT)


; superblock _ondisk_ structure (xfs_sb.h)
; this is _not_ the partition structure
; for XFS partition structure see XFS below
struct xfs_sb
        sb_magicnum     dd ?    ; signature, must be XFS_SB_MAGIC
        sb_blocksize    dd ?    ; block is the minimal file system unit, in bytes
        sb_dblocks      dq ?    ; number of data blocks
        sb_rblocks      dq ?    ; number of realtime blocks (not supported yet!)
        sb_rextents     dq ?    ; number of realtime extents (not supported yet!)
        sb_uuid         rb 16   ; file system unique identifier
        sb_logstart     dq ?    ; starting block of log (for internal journal; journals on separate devices are not supported!)
        sb_rootino      dq ?    ; root inode number
        sb_rbmino       dq ?    ; bitmap inode for realtime extents (ignored)
        sb_rsumino      dq ?    ; summary inode for rt bitmap (ignored)
        sb_rextsize     dd ?    ; realtime extent size, blocks
        sb_agblocks     dd ?    ; size of an allocation group (the last one may be smaller!)
        sb_agcount      dd ?    ; number of allocation groups
        sb_rbmblocks    dd ?    ; number of rt bitmap blocks
        sb_logblocks    dd ?    ; number of log blocks
        sb_versionnum   dw ?    ; header version == XFS_SB_VERSION
        sb_sectsize     dw ?    ; volume sector size in bytes (only 512B sectors are supported)
        sb_inodesize    dw ?    ; inode size, bytes
        sb_inopblock    dw ?    ; inodes per block
        sb_fname        rb 12   ; inodes per block (aka label)
        sb_blocklog     db ?    ; log2 of sb_blocksize
        sb_sectlog      db ?    ; log2 of sb_blocksize
        sb_inodelog     db ?    ; log2 of sb_inodesize
        sb_inopblog     db ?    ; log2 of sb_inopblock
        sb_agblklog     db ?    ; log2 of sb_agblocks (rounded up!)
        sb_rextslog     db ?    ; log2 of sb_rextents
        sb_inprogress   db ?    ; mkfs is in progress, don't mount
        sb_imax_pct     db ?    ; max % of fs for inode space
        ; statistics
        sb_icount       dq ?    ; allocated inodes
        sb_ifree        dq ?    ; free inodes
        sb_fdblocks     dq ?    ; free data blocks
        sb_frextents    dq ?    ; free realtime extents

        sb_uquotino     dq ?    ; user quota inode
        sb_gquotino     dq ?    ; group quota inode
        sb_qflags       dw ?    ; quota flags
        sb_flags        db ?    ; misc. flags
        sb_shared_vn    db ?    ; shared version number
        sb_inoalignmt   dd ?    ; inode chunk alignment, fsblocks
        sb_unit         dd ?    ; stripe or raid unit
        sb_width        dd ?    ; stripe or raid width
        sb_dirblklog    db ?    ; log2 of dir block size (fsbs)
        sb_logsectlog   db ?    ; log2 of the log sector size
        sb_logsectsize  dw ?    ; sector size for the log, bytes
        sb_logsunit     dd ?    ; stripe unit size for the log
        sb_features2    dd ?    ; additional feature bits
ends


; allocation group inode (xfs_ag.h)
struct xfs_agi
        agi_magicnum    dd ?    ; magic number == XFS_AGI_MAGIC
        agi_versionnum  dd ?    ; header version == XFS_AGI_VERSION
        agi_seqno       dd ?    ; sequence number starting from 0
        agi_length      dd ?    ; size in blocks of a.g.
        agi_count       dd ?    ; count of allocated inodes
        agi_root        dd ?    ; root of inode btree
        agi_level       dd ?    ; levels in inode btree
        agi_freecount   dd ?    ; number of free inodes
        agi_newino      dd ?    ; new inode just allocated
        agi_dirino      dd ?    ; last directory inode chunk
        agi_unlinked    rd XFS_AGI_UNLINKED_BUCKETS     ; Hash table of inodes which have been unlinked but are still being referenced
ends


; superblock structure of b+tree node/leaf (same structure, bb_level matters)
struct xfs_btree_sblock
        bb_magic        dd ?
        bb_level        dw ?    ; distinguishes nodeds and leaves
        bb_numrecs      dw ?
        bb_leftsib      dd ?
        bb_rightsib     dd ?
ends


; record of b+tree inode
struct xfs_inobt_rec
        ir_startino     dd ?
        ir_freecount    dd ?
        ir_free         dq ?
ends


; structure to store create, access and modification time in inode core
struct xfs_timestamp
        t_sec           dd ?
        t_nsec          dd ?    ; nanoseconds
ends


; inode core structure: basic information about file
struct xfs_dinode_core
        di_magic        dw ?            ; inode magic = XFS_DINODE_MAGIC
        di_mode         dw ?            ; mode and type of file
        di_version      db ?            ; inode version
        di_format       db ?            ; format of di_c data
        di_onlink       dw ?            ; old number of links to file
        di_uid          dd ?            ; owner's user id
        di_gid          dd ?            ; owner's group id
        di_nlink        dd ?            ; number of links to file
        di_projid       dw ?            ; owner's project id
        di_pad          rb 8            ; unused, zeroed space
        di_flushiter    dw ?            ; incremented on flush
        di_atime        xfs_timestamp   ; time last accessed
        di_mtime        xfs_timestamp   ; time last modified
        di_ctime        xfs_timestamp   ; time created/inode modified
        di_size         dq ?            ; number of bytes in file
        di_nblocks      dq ?            ; number of direct & btree blocks used
        di_extsize      dd ?            ; basic/minimum extent size for file
        di_nextents     dd ?            ; number of extents in data fork
        di_anextents    dw ?            ; number of extents in attribute fork
        di_forkoff      db ?            ; attr fork offs, <<3 for 64b align
        di_aformat      db ?            ; format of attr fork's data
        di_dmevmask     dd ?            ; DMIG event mask
        di_dmstate      dw ?            ; DMIG state info
        di_flags        dw ?            ; random flags, XFS_DIFLAG_...
        di_gen          dd ?            ; generation number
ends


; shortform dir header
struct xfs_dir2_sf_hdr
        count           db ?            ; the number of directory entries, used only if each inode number fits 4 bytes; zero otherwise
        i8count         db ?            ; the number of directory entries, used only when count is zero
        parent          dq ?            ; parent inode number: xfs_dir2_inou_t (4 or 8 bytes)
ends         


; shortform dir entry
struct xfs_dir2_sf_entry
        namelen         db ?            ; actual name length (ASCII)
        offset          rb 2            ; saved offset
        name            db ?            ; name, variable size
;       inumber         dq ?            ; xfs_dir2_inou_t
ends


; active entry in a data block
; aligned to 8 bytes
; tag appears as the last 2 bytes
struct xfs_dir2_data_entry
        inumber         dq ?            ; inode number
        namelen         db ?            ; name length
        name            db ?            ; name bytes, no null
;       tag             dw ?            ; starting offset of us
ends


; unused entry in a data block
; aligned to 8 bytes
; tag appears as the last 2 bytes
struct xfs_dir2_data_unused
        freetag         dw ?            ; XFS_DIR2_DATA_FREE_TAG
        length          dw ?            ; total free length
;        tag             dw ?           ; starting offset of us
ends


; generic data entry
struct xfs_dir2_data_union
  union
        xentry          xfs_dir2_data_entry
        unused          xfs_dir2_data_unused
  ends
ends


; describe a free area in the data block
; the freespace will be formatted as a xfs_dir2_data_unused_t
struct xfs_dir2_data_free
        offset          dw ?            ; start of freespace
        length          dw ?            ; length of freespace
ends


; header for the data blocks
; always at the beginning of a directory-sized block
; the code knows that XFS_DIR2_DATA_FD_COUNT is 3
struct xfs_dir2_data_hdr
        magic           dd ?                    ; XFS_DIR2_DATA_MAGIC or XFS_DIR2_BLOCK_MAGIC
        bestfree        xfs_dir2_data_free
        bestfree2       xfs_dir2_data_free
        bestfree3       xfs_dir2_data_free
ends


; leaf block entry
struct xfs_dir2_leaf_entry
        hashval         dd ?            ; hash value of name
        address         dd ?            ; address of data entry
ends


; the tail of directory block
struct xfs_dir2_block_tail
        count           dd ?            ; count of leaf entries
        stale           dd ?            ; count of stale leaf entries
ends


; generic single-block structure, for xfs_db
struct xfs_dir2_block
        hdr             xfs_dir2_data_hdr
        u               xfs_dir2_data_union
;        leaf            xfs_dir2_leaf_entry
;        tail            xfs_dir2_block_tail
ends


; 
struct xfs_dir2_data
        hdr             xfs_dir2_data_hdr       ; magic XFS_DIR2_DATA_MAGIC
        u               xfs_dir2_data_union
ends


; 
struct xfs_da_blkinfo
        forw            dd ?            ; previous block in list
        back            dd ?            ; following block in list
        magic           dw ?            ; validity check on block
        pad             dw ?            ; unused
ends


; leaf block header
struct xfs_dir2_leaf_hdr
        info            xfs_da_blkinfo  ; header for da routines
        count           dw ?            ; count of entries
        stale           dw ?            ; count of stale entries
ends


; leaf block tail
struct xfs_dir2_leaf_tail
        bestcount       dd ?
ends


; leaf block
; bests and tail are at the end of the block for single-leaf only
; (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC)
struct xfs_dir2_leaf
        hdr             xfs_dir2_leaf_hdr       ; leaf header
        ents            xfs_dir2_leaf_entry     ; entries
;       bests           dw ?                    ; best free counts
;       tail            xfs_dir2_leaf_tail      ; leaf tail
ends


; header of 'free' block part
struct xfs_dir2_free_hdr
        magic           dd ?    ; XFS_DIR2_FREE_MAGIC
        firstdb         dd ?    ; db of first entry
        nvalid          dd ?    ; count of valid entries
        nused           dd ?    ; count of used entries
ends


; 'free' part of directiry block
struct xfs_dir2_free
        hdr             xfs_dir2_free_hdr       ; block header
        bests           dw ?                    ; best free counts
                                                ; unused entries are -1 (XFS_NULL)
ends


; b+tree node header
struct xfs_da_node_hdr
        info            xfs_da_blkinfo
        count           dw ?
        level           dw ?
ends


; b+tree node
struct xfs_da_node_entry
        hashval         dd ?            ; hash value for this descendant
        before          dd ?            ; Btree block before this key
ends


; 
struct xfs_da_intnode
        hdr             xfs_da_node_hdr
        btree           xfs_da_node_entry
ends


; packet extent
struct xfs_bmbt_rec
        l0              dq ?
        l1              dq ?
ends


; unpacked extent
struct xfs_bmbt_irec
        br_startoff     dq ?            ; starting file offset
        br_startblock   dq ?            ; starting block number
        br_blockcount   dd ?            ; number of blocks
        br_state        dd ?            ; extent state
ends


; bmap root header, on-disk form only
struct xfs_bmdr_block
        bb_level        dw ?            ; 0 is a leaf
        bb_numrecs      dw ?            ; current number of data records
ends


; key structure for non-leaf levels of the tree
struct xfs_bmbt_key
        br_startoff     dq ?            ; starting file offset
ends


sizeof.xfs_bmbt_ptr = 8                 ; workaround
sizeof.xfs_bmdr_ptr = 8                 ; workaround


; long form header: bmap btrees
; xfs_btree_lblock is xfs_bmbt_block (xfs_btree.h)
struct xfs_bmbt_block
        bb_magic        dd ?            ; magic number for block type
        bb_level        dw ?            ; 0 is a leaf
        bb_numrecs      dw ?            ; current number of data records
        bb_leftsib      dq ?            ; left sibling block or NULLDFSBNO
        bb_rightsib     dq ?            ; right sibling block or NULLDFSBNO
ends


; high level inode structure
struct xfs_inode
        di_core                 xfs_dinode_core ; main info, aka core
        di_next_unlinked        dd ?            ; unlinked but still used inode (if any, XFS_NULL otherwise)
        di_u                    db ?            ; data fork inode part
;        di_a                    db ?           ; data attribute
ends


; internal data for every XFS partition
; this _is_ XFS partition structure
; most fields are unpacked or bswap'ed values from the superblock, so see xfs_sb structure above
struct XFS PARTITION
        Lock                    MUTEX ?         ; access mutex
        blocksize               dd ?
        sectsize                dd ?
        dirblocksize            dd ?
        rootino                 dq ?
        cur_block               dd ?
        cur_inode               dd ?
        cur_sect                dd ?
        cur_dirblock            dd ?
        tmp_inode               dd ?
        versionnum              dd ?
        features2               dd ?
        inodesize               dd ?
        inopblock               dd ?
        blocklog                dd ?
        sectlog                 dd ?
        inodelog                dd ?
        inopblog                dd ?
        agblklog                dd ?
        blockmsectlog           dd ?
        inodetoblocklog         dd ?
        dirblklog               dd ?
        sectpblock              dd ?
        agblocks                dd ?
        ; helpers, temporary vars, etc
        agblockmask             dq ?
        extent                  xfs_bmbt_irec
        left_extents            dd ?
        left_leaves             dd ?
        bytes_to_read           dd ?
        bytes_read              dd ?
        entries_read            dd ?
        file_offset             dq ?
        max_dirblockaddr        dd ?
        next_block_num          dq ?
        dir2_leaf_offset_blocks dd ?
        dir2_free_offset_blocks dd ?
        cur_inode_save          dd ?
        bytes_left_in_file      dq ?
        ro_nextents             dd ?
        bb_ptrs                 dd ?
        maxnumrecs              dd ?
        buffer_pos              dd ?
        eof                     dd ?
ends