Module: XFS

Included in:
FileObject
Defined in:
lib/fs/MiqFS/modules/XFS.rb,
lib/fs/xfs/inode.rb,
lib/fs/xfs/directory.rb,
lib/fs/xfs/inode_map.rb,
lib/fs/xfs/superblock.rb,
lib/fs/xfs/directory_entry.rb,
lib/fs/xfs/allocation_group.rb,
lib/fs/xfs/bmap_btree_block.rb,
lib/fs/xfs/bmap_btree_record.rb,
lib/fs/xfs/short_form_header.rb,
lib/fs/xfs/bmap_btree_root_node.rb,
lib/fs/xfs/directory_block_tail.rb,
lib/fs/xfs/directory_data_header.rb,
lib/fs/xfs/directory2_data_header.rb,
lib/fs/xfs/directory3_data_header.rb,
lib/fs/xfs/short_form_directory_entry.rb

Overview

XFS file system interface to MiqFS.

Defined Under Namespace

Classes: AllocationGroup, BmapBTreeBlock, BmapBTreeRecord, BmapBTreeRootNode, Directory, Directory2DataHeader, Directory3DataHeader, DirectoryBlockTail, DirectoryDataHeader, DirectoryEntry, FileObject, Inode, InodeMap, ShortFormDirectoryEntry, ShortFormHeader, Superblock

Constant Summary collapse

TIMESTAMP =
BinaryStruct.new([
  'I',  'seconds',           # timestamp seconds
  'I',  'nanoseconds',       # timestamp nanoseconds
])
INODE =
BinaryStruct.new([
  'S>',  'magic',             # Inode Magic Number
  'S>',  'file_mode',         # Mode and Type of file
  'C',   'version',           # Inode Version
  'C',   'format',            # Format of Data Fork Data
  'S>',  'old_num_links',     # Old Number of Links to File
  'I>',  'uid',               # Owner's User Id
  'I>',  'gid',               # Owner's Group Id
  'I>',  'num_links',         # Number of Links to File
  'S>',  'projid_low',        # Lower Part of Owner's Project Id
  'S>',  'projid_high',       # Higher Part of Owner's Project Id
  'a6',  'pad',               # Unused, Zeroed Space
  'S>',  'flush_iterator',    # Incremented on Flush
  'I>',  'atime_secs',        # time last accessed seconds
  'I>',  'atime_nsecs',       # time last accessed nanoseconds
  'I>',  'mtime_secs',        # time last modified seconds
  'I>',  'mtime_nsecs',       # time last modified nanoseconds
  'I>',  'ctime_secs',        # time created / inode modified seconds
  'I>',  'ctime_nsecs',       # time created / inode modified nanoseconds
  'Q>',  'size',              # number of bytes in file
  'Q>',  'nblocks',           # Number of direct & btree blocks used
  'I>',  'extent_size',       # Basic/Minimum extent size for file
  'I>',  'num_extents',       # Number of extents in data fork
  'S>',  'attr_num_extents',  # Number of extents in attribute fork
  'C',   'attr_fork_offset',  # Attribute Fork Offset, <<3 for 64b align
  'c',   'attr_fork_format',  # Format of Attribute Fork's Data
  'I>',  'dmig_event_mask',   # DMIG event mask
  'S>',  'dmig_state_info',   # DMIG state info
  'S>',  'flags',             # random flags, XFS_DIFLAG_...
  'I>',  'gen_num',           # generation number
  'I>',  'next_unlinked',     # agi unlinked list ptr
])
EXTENDED_INODE =
BinaryStruct.new([
  'S>',  'magic',             # Inode Magic Number
  'S>',  'file_mode',         # Mode and Type of file
  'C',   'version',           # Inode Version
  'C',   'format',            # Format of Data Fork Data
  'S>',  'old_num_links',     # Old Number of Links to File
  'I>',  'uid',               # Owner's User Id
  'I>',  'gid',               # Owner's Group Id
  'I>',  'num_links',         # Number of Links to File
  'S>',  'projid_low',        # Lower Part of Owner's Project Id
  'S>',  'projid_high',       # Higher Part of Owner's Project Id
  'a6',  'pad',               # Unused, Zeroed Space
  'S>',  'flush_iterator',    # Incremented on Flush
  'I>',  'atime_secs',        # time last accessed seconds
  'I>',  'atime_nsecs',       # time last accessed nanoseconds
  'I>',  'mtime_secs',        # time last modified seconds
  'I>',  'mtime_nsecs',       # time last modified nanoseconds
  'I>',  'ctime_secs',        # time created / inode modified seconds
  'I>',  'ctime_nsecs',       # time created / inode modified nanoseconds
  'Q>',  'size',              # number of bytes in file
  'Q>',  'nblocks',           # Number of direct & btree blocks used
  'I>',  'extent_size',       # Basic/Minimum extent size for file
  'I>',  'num_extents',       # Number of extents in data fork
  'S>',  'attr_num_extents',  # Number of extents in attribute fork
  'C',   'attr_fork_offset',  # Attribute Fork Offset, <<3 for 64b align
  'c',   'attr_fork_format',  # Format of Attribute Fork's Data
  'I>',  'dmig_event_mask',   # DMIG event mask
  'S>',  'dmig_state_info',   # DMIG state info
  'S>',  'flags',             # random flags, XFS_DIFLAG_...
  'I>',  'gen_num',           # generation number
  'I>',  'next_unlinked',     # agi unlinked list ptr
  'I>',  'crc',               # CRC of the inode
  'Q>',  'change_count',      # number of attribute changes
  'Q>',  'lsn',               # flush sequence
  'Q>',  'flags2',            # more random flags
  'a16', 'pad2',              # more padding for future expansion
  'I>',  'crtime_secs',       # time created seconds
  'I>',  'crtime_nsecs',      # time created nanoseconds
  'Q>',  'inode_number',      # inode number
  'a16', 'uuid',              # UUID of the filesystem
])
SIZEOF_INODE =
INODE.size
SIZEOF_EXTENDED_INODE =
EXTENDED_INODE.size
DIRECTORY_LEAF_ENTRY =
BinaryStruct.new([
  'I>', 'hashval',               # hash value of name
  'I>', 'address',               # address of data entry
])
SIZEOF_DIRECTORY_LEAF_ENTRY =
DIRECTORY_LEAF_ENTRY.size
SUPERBLOCK =

//////////////////////////////////////////////////////////////////////////// // Data definitions. Linux 2.6.2 from Fedora Core 6.

BinaryStruct.new([
  'L>',  'magic_num',          # magic number of the filesystem
  'L>',  'block_size',         # size of a basic unit of space allocation in bytes
  'Q>',  'data_blocks',        # total Number of blocks available for data and metadata
  'Q>',  'realtime_blocks',    # number of blocks on the real-time disk device
  'Q>',  'realtime_extents',   # Number of extents on the real-time disk device
  'a16',  'uuid',              # UUID for the filesystem
  'Q>',  'log_start',          # first block for the journal log if internal (0 if external)
  'Q>',  'root_inode_num',     # root inode number for the filesystem
  'Q>',  'bitmap_inode_num',   # bitmap inode number for real-time extents
  'Q>',  'summary_inode_num',  # summary inode number for real-time bitmap
  'L>',  'realtime_ext_size',  # real-time extent size in blocks
  'L>',  'ag_blocks',          # size of each allocation group in blocks
  'L>',  'ag_count',           # number of allocation groups in the filesystem
  'L>',  'bitmap_blocks',      # number of real-time bitmap blocks
  'L>',  'log_blocks',         # number of blocks for the journaling log
  'S>',  'version_number',     # Filesystem version number
  'S>',  'sector_size',        # underlying disk sector size in bytes
  'S>',  'inode_size',         # size of the inode in bytes
  'S>',  'inodes_per_blk',     # number of inodes per block
  'a12',  'fs_name',           # name for the filesystem
  'C',   'block_size_log',     # log base 2 of block_size
  'C',   'sector_size_log',    # log base 2 of sector_size
  'C',   'inode_size_log',     # log base 2 of inode_size
  'C',   'inodes_per_blk_log', # log base 2 of inodes_per_blk
  'C',   'ag_blocks_log',      # log base 2 of ag_blocks (rounded up)
  'C',   'rt_ext_size_log',    # log base 2 of realtime_ext_size
  'C',   'in_progress',        # flag specifying that the filesystem is being created
  'C',   'inode_max_pct',      # maximum percentage of filesystem space that can be used for inodes
  'Q>',  'inode_count',        # global count for number of inodes allocated on the filesystem
  'Q>',  'inode_free_count',   # global count of free inodes on the filesystem.
  'Q>',  'free_data_blocks',   # global count of free data blocks on the filesystem
  'Q>',  'free_rt_extents',    # global count of free real-time extents on the filesystem
  'Q>',  'user_quota_ino',     # inode number for user quotas
  'Q>',  'group_quota_ino',    # inode number for group quotas
  'S>',  'quota_flags',        # quota flags
  'C',   'misc_flags',         # miscellaneous flags
  'C',   'shared_vers_no',     # shared version number
  'L>',  'inode_alignment',    # inode chunk alignment in blocks
  'L>',  'stripe_unit',        # underlying stripe or raid unit in blocks
  'L>',  'stripe_width',       # underlying stripe or raid width in blocks
  'C',   'dir_block_log',      # log base 2 multiplier that determines the
  # granularity of directory block allocations in fsblocks
  'C',   'log_sect_size_log',  # log base 2 of the log subvolume's sector size
  'S>',  'log_sector_size',    # the log's sector size in bytes if the filesystem uses an external log device
  'L>',  'log_stripe_unit_sz', # the log device's stripe or raid unit size.
  'L>',  'features_2',         # add'l version flags if XFS_SUPERBLOCK_VERSION_MOREBITSBIT is set in version_number
  # version 5 superblock fields start here
  'L>',  'features_compat',
  'L>',  'features_ro_compat',
  'L>',  'features_incompat',
  'L>',  'features_log_incompat',
  'L>',  'superblock_crc',     # superblock crc
  'L>',  'padding',
  'Q>',  'proj_quota_ino',     # inode number for project quotas
  'q>',  'last_write_seq',     # last write sequence
])
SUPERBLOCK_SIZE =
512
DEF_CACHE_SIZE =

Default directory cache size.

500
DIRECTORY2_DATA_ENTRY =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

Active entry in a data block. Aligned to 8 bytes. A variable length name field follows the length. After the name there is a 2 byte tag field. For dir3 structures, there is a 1 byte file type field between the name and the tag. It is packed hard against the end of the name so any padding for rounding is between the file type and the tag.

BinaryStruct.new([
  'Q>',  'inumber',   # inode number
  'C',   'name_len',  # name length
])
SIZEOF_DIRECTORY2_DATA_ENTRY =
DIRECTORY2_DATA_ENTRY.size
DIRECTORY2_DATA_TAG =
BinaryStruct.new([
  'S>',  'tag',       # tag
])
SIZEOF_DIRECTORY2_DATA_TAG =
DIRECTORY2_DATA_TAG.size
DIRECTORY2_UNUSED_ENTRY =
BinaryStruct.new([
  'S>',  'freetag',   # 0xFFFF if unused
  'S>',  'length',    # length of this free entry
])
SIZEOF_DIRECTORY2_UNUSED_ENTRY =
DIRECTORY2_UNUSED_ENTRY.size
AG_FREESPACE =

////////////////////////////////////////////////////////////////////////////

BinaryStruct.new([
  #  Common allocation group header information
  'I>',  'magic_num',          # magic number of the filesystem
  'I>',  'version_num',        # header version
  'I>',  'seq_no',             # sequence # starting from 0
  'I>',  'length',             # size in blocks of a.g.
  #  Freespace Information
  #
  'I>2', 'root_blocks',        # Root Blocks
  'I>',  'spare0',             # spare field
  'I>2', 'btree_levels',       # btree levels
  'I>',  'spare1',             # spare field
  'I>',  'fl_first',           # first freelist block's index
  'I>',  'fl_last',            # last freelist block's index
  'I>',  'fl_count',           # count of blocks in freelist
  'I>',  'free_blocks',        # total free blocks
  'L>',  'longest',            # longest free space
  'L>',  'btree_blocks',       # # of blocks held in alloc group free btrees
  'a16', 'uuid',               # Filesystem uuid
  #
  # Reserve some contiguous space for future logged fields before we add
  # the unlogged fields.  This makes the range logging via flags and
  # structure offsets much simpler.
  #
  'Q>16', 'spare64',           # underlying disk sector size in bytes
  #
  # Unlogged fields, written during buffer writeback.
  #
  'Q>',  'last_write_seq',     # last write sequence
  'I>',  'crc',                # CRC of alloc group free space sector
  'I>',  'spare2',             # name for the filesystem
])
AG_INODEINFO =
BinaryStruct.new([
  #  Common allocation group header information
  'I>',  'magic_num',          # magic number of the filesystem
  'I>',  'version_num',        # header version
  'I>',  'seq_no',             # sequence # starting from 0
  'I>',  'length',             # size in blocks of a.g.
  #
  #  Inode information
  #  Inodes are mapped by interpretting the inode number, so no
  #  mapping data is needed here.
  #
  'I>',  'count',              # count of allocated inodes
  'I>',  'root',               # root of inode btree
  'I>',  'level',              # levels in inode btree
  'I>',  'free_count',         # number of free inodes
  'I>',  'new_inode',          # new inode just allocated
  'I>',  'dir_inode',          # last directory inode chunk
  #
  # Hash table of inodes which have been unlinked but are
  # still being referenced.
  #
  'I>64', 'unlinked_hash',     # the hash
  'a16', 'uuid',               # Filesystem uuid
  'I>',  'crc',                # CRC of alloc group inode info sector
  'I>',  'pad32',              #
  'Q>',  'last_write_seq',     # last write sequence
  'I>',  'free_root',          # root of the free inode btree
  'I>',  'free_level',         # levels in free inode btree
])
AG_FREELIST =

The third AG block contains the AG FreeList, an array of block pointers to blocks owned by the allocation btree code.

BinaryStruct.new([
  'I>',  'magic_num',          # magic number of the filesystem
  'I>',  'seq_no',             # sequence # starting from 0
  'a16', 'uuid',               # Filesystem uuid
  'Q>',  'last_write_seq',     # last write sequence
  'I>',  'crc',                # CRC of alloc group inode info sector
  'I>',  'bno',                # actually XFS_AGFL_SIZE
])
AG_FL_STRUCT_SIZE =
AG_FREELIST.size
BTREE_BLOCK_SHORT_NOCRC =

////////////////////////////////////////////////////////////////////////////

BinaryStruct.new([
  #  Common BTree Block header information
  'I>',  'magic_num',          # magic number of the btree block type
  'S>',  'level',              # level number.  0 is a leaf
  'S>',  'num_recs',           # current # of data records
  #
  #  Short Section
  #
  'I>',  'left_sibling',       #
  'I>',  'right_sibling',      #
])
SIZEOF_BTREE_BLOCK_SHORT_NOCRC =
BTREE_BLOCK_SHORT_NOCRC.size
BTREE_BLOCK_SHORT =
BinaryStruct.new([
  #  Common BTree Block header information
  'I>',  'magic_num',          # magic number of the btree block type
  'S>',  'level',              # level number.  0 is a leaf
  'S>',  'num_recs',           # current # of data records
  #
  #  Short Section
  #
  'I>',  'left_sibling',       #
  'I>',  'right_sibling',      #
  'Q>',  'block_num',          #
  'Q>',  'lsn',                #
  'a16', 'uuid',               #
  'I>',  'owner',              #
  'I>',  'crc',                #
])
SIZEOF_BTREE_BLOCK_SHORT =
BTREE_BLOCK_SHORT.size
BTREE_BLOCK_LONG_NOCRC =
BinaryStruct.new([
  #  Common BTree Block header information
  'I>',  'magic_num',          # magic number of the btree block type
  'S>',  'level',              # level number.  0 is a leaf
  'S>',  'num_recs',           # current # of data records
  #
  #  Long Section
  #
  'Q>',  'left_sibling',       #
  'Q>',  'right_sibling',      #
])
SIZEOF_BTREE_BLOCK_LONG_NOCRC =
BTREE_BLOCK_LONG_NOCRC.size
BTREE_BLOCK_LONG =
BinaryStruct.new([
  #  Common BTree Block header information
  'I>',  'magic_num',          # magic number of the btree block type
  'S>',  'level',              # level number.  0 is a leaf
  'S>',  'num_recs',           # current # of data records
  #
  #  Long Section
  #
  'Q>',  'left_sibling',       #
  'Q>',  'right_sibling',      #
  'Q>',  'block_num',          #
  'Q>',  'lsn',                #
  'a16', 'uuid',               #
  'Q>',  'owner',              #
  'I>',  'crc',                #
  'I>',  'pad',                #
])
SIZEOF_BTREE_BLOCK_LONG =
BTREE_BLOCK_LONG.size
BMAP_BTREE_REC =
BinaryStruct.new([
  'Q>',          'l0',
  'Q>',          'l1',
])
SIZEOF_BMAP_BTREE_REC =
16
DIRECTORY_SHORTERFORM_HEADER =

Directory Entry when stored internal to an inode. Small directories are packed as tightly as possible so as to fit into the literal area of the inode. These “shortform” directories consist of a single header followed by zero or more dir entries. Due to the different inode number storage size and the variable length name field in the dir entry all these structures are variable length, and the accessors in this file should be used to iterate over them.

BinaryStruct.new([
  'C',  'entry_count',         # count of entries
  'C',  'i8byte_count',        # count of 8-byte inode #s
  'I>', 'parent_ino_4byte',    # parent dir inode # stored as 4 8-bit values
])
SIZEOF_DIRECTORY_SHORTERFORM_HEADER =
DIRECTORY_SHORTERFORM_HEADER.size
DIRECTORY_SHORTFORM_HEADER =
BinaryStruct.new([
  'C',  'entry_count',         # count of entries
  'C',  'i8byte_count',        # count of 8-byte inode #s
  'Q>', 'parent_ino_8byte',    # parent dir inode # stored as 8 8-bit values
])
SIZEOF_DIRECTORY_SHORTFORM_HEADER =
DIRECTORY_SHORTFORM_HEADER.size
BMAP_BTREE_ROOT_NODE_HEADER =
BinaryStruct.new([
  'S>',          'level',           # B+Tree Level
  'S>',          'entry_count',     # Number of Key and Pointer Array Elements
])
SIZEOF_BMAP_BTREE_ROOT_NODE_HEADER =
BMAP_BTREE_ROOT_NODE_HEADER.size
BMAP_BTREE_ROOT_NODE_ENTRIES =

Note that the following 3 entries are used simply to compute the maximum number of records possible in the on-disk inode.

BinaryStruct.new([
  'Q>',          'starting_offset', # starting offset of the block
  'Q>',          'block_number',    # block number of the entry
])
SIZEOF_BMAP_BTREE_ROOT_NODE_ENTRIES =
BMAP_BTREE_ROOT_NODE_ENTRIES.size
BMAP_BTREE_ROOT_NODE_OFFSET =
BinaryStruct.new([
  'Q>',          'starting_offset',  # starting offset of the block
])
SIZEOF_BMAP_BTREE_ROOT_NODE_OFFSET =
BMAP_BTREE_ROOT_NODE_OFFSET.size
BMAP_BTREE_ROOT_NODE_BLOCK =
BinaryStruct.new([
  'Q>',          'block_number',     # block number of the entry
])
SIZEOF_BMAP_BTREE_ROOT_NODE_BLOCK =
BMAP_BTREE_ROOT_NODE_BLOCK.size
DIRECTORY_BLOCK_TAIL =

xfs_dir2_data_hdr consists of the magic number followed by 3 copies of the xfs_dir2_data_free structure

BinaryStruct.new([
  'I>', 'count',               # total number of leaf entries
  'I>', 'stale',               # total number of free entries
])
SIZEOF_DIRECTORY_BLOCK_TAIL =
DIRECTORY_BLOCK_TAIL.size
DIRECTORY_DATA_FREE =
BinaryStruct.new([
  'S>',  'offset',              # start of freespace
  'S>',  'length',              # length of freespace
])
SIZEOF_DIRECTORY_DATA_FREE =
DIRECTORY_DATA_FREE.size
DIRECTORY2_DATA_HEADER =

xfs_dir2_data_hdr consists of the magic number followed by 3 copies of the xfs_dir2_data_free structure

BinaryStruct.new([
  'I>', 'magic',               # magic number
])
SIZEOF_DIRECTORY2_DATA_HEADER =
DIRECTORY2_DATA_HEADER.size
DIRECTORY3_DATA_HEADER =
BinaryStruct.new([
  'I>',  'magic',               # magic number
  'I>',  'crc',                 # CRC of block
  'Q>',  'block_number',        # first block of the buffer
  'Q>',  'last_write_sequence', # sequence number of last write
  'a16', 'uuid',                # filesystem we belong to
  'Q>',  'owner',               # inode that owns the block
])
SIZEOF_DIRECTORY3_DATA_HEADER =
DIRECTORY3_DATA_HEADER.size
DIRECTORY3_DATA_PAD =
BinaryStruct.new([
  'I>',  'padding',             # padding
])
SIZEOF_DIRECTORY3_DATA_PAD =
DIRECTORY3_DATA_PAD.size
SHORT_FORM_DIRECTORY_ENTRY =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

Short Form Directory Entry in a Short Form Inode.

BinaryStruct.new([
  'C',   'name_length',  # name length
  'C',   'offset_byte0',
  'C',   'offset_byte1',
])
SIZEOF_SHORT_FORM_DIRECTORY_ENTRY =
SHORT_FORM_DIRECTORY_ENTRY.size
SHORT_FORM_SHORT_INO =
BinaryStruct.new([
  'I>',  'inode_num', # 4 byte inode number
])
SIZEOF_SHORT_FORM_SHORT_INO =
SHORT_FORM_SHORT_INO.size
SHORT_FORM_LONG_INO =
BinaryStruct.new([
  'Q>',  'inode_num', # 8 byte inode number
])
SIZEOF_SHORT_FORM_LONG_INO =
SHORT_FORM_LONG_INO.size

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#cache_hitsObject

Members (these become members of an MiqFS instance).



13
14
15
# File 'lib/fs/MiqFS/modules/XFS.rb', line 13

def cache_hits
  @cache_hits
end

#dir_cacheObject

Members (these become members of an MiqFS instance).



13
14
15
# File 'lib/fs/MiqFS/modules/XFS.rb', line 13

def dir_cache
  @dir_cache
end

#entry_cacheObject

Members (these become members of an MiqFS instance).



13
14
15
# File 'lib/fs/MiqFS/modules/XFS.rb', line 13

def entry_cache
  @entry_cache
end

#rootDirObject

Members (these become members of an MiqFS instance).



13
14
15
# File 'lib/fs/MiqFS/modules/XFS.rb', line 13

def rootDir
  @rootDir
end

#superblockObject

Members (these become members of an MiqFS instance).



13
14
15
# File 'lib/fs/MiqFS/modules/XFS.rb', line 13

def superblock
  @superblock
end

Instance Method Details

#fs_dirEntries(p) ⇒ Object

Returns String array of all names, sans path. TODO



66
67
68
69
70
71
# File 'lib/fs/MiqFS/modules/XFS.rb', line 66

def fs_dirEntries(p)
  # Get path directory.
  dir = ifs_getDir(p)
  return nil if dir.nil?
  dir.glob_names
end

#fs_dirMkdir(_p) ⇒ Object

Make a directory. Parent must exist. TODO



75
76
77
# File 'lib/fs/MiqFS/modules/XFS.rb', line 75

def fs_dirMkdir(_p)
  raise "Write functionality is not yet supported on XFS."
end

#fs_dirRmdir(_p) ⇒ Object

Remove a directory. TODO



81
82
83
# File 'lib/fs/MiqFS/modules/XFS.rb', line 81

def fs_dirRmdir(_p)
  raise "Write functionality is not yet supported on XFS."
end

#fs_fileAtime(p) ⇒ Object

Returns Ruby Time object.



123
124
125
126
127
# File 'lib/fs/MiqFS/modules/XFS.rb', line 123

def fs_fileAtime(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.get_inode(de.inode).aTime
end

#fs_fileAtime_obj(fobj) ⇒ Object

Returns a Ruby Time object.



156
157
158
# File 'lib/fs/MiqFS/modules/XFS.rb', line 156

def fs_fileAtime_obj(fobj)
  fobj.inode.access_time
end

#fs_fileClose(fobj) ⇒ Object

Write changes & destroy.



195
196
197
198
199
200
# File 'lib/fs/MiqFS/modules/XFS.rb', line 195

def fs_fileClose(fobj)
  # TODO: unrem when write is supported.
  # fobj.inode.close
  fobj.inode.rewind
  nil
end

#fs_fileCtime(p) ⇒ Object

Returns Ruby Time object.



130
131
132
133
134
# File 'lib/fs/MiqFS/modules/XFS.rb', line 130

def fs_fileCtime(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.get_inode(de.inode).cTime
end

#fs_fileCtime_obj(fobj) ⇒ Object

Returns a Ruby Time object.



161
162
163
# File 'lib/fs/MiqFS/modules/XFS.rb', line 161

def fs_fileCtime_obj(fobj)
  fobj.inode.create_time
end

#fs_fileDelete(_p) ⇒ Object

Delete file.



118
119
120
# File 'lib/fs/MiqFS/modules/XFS.rb', line 118

def fs_fileDelete(_p)
  raise "Write functionality is not yet supported on XFS."
end

#fs_fileDirectory?(p) ⇒ Boolean

Returns true if name is a directory.

Returns:

  • (Boolean)


104
105
106
107
108
# File 'lib/fs/MiqFS/modules/XFS.rb', line 104

def fs_fileDirectory?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  de.file_type == Inode::FT_DIRECTORY
end

#fs_fileExists?(p) ⇒ Boolean

Returns true if name exists, false if not.

Returns:

  • (Boolean)


90
91
92
93
94
# File 'lib/fs/MiqFS/modules/XFS.rb', line 90

def fs_fileExists?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  true
end

#fs_fileFile?(p) ⇒ Boolean

Returns true if name is a regular file.

Returns:

  • (Boolean)


97
98
99
100
101
# File 'lib/fs/MiqFS/modules/XFS.rb', line 97

def fs_fileFile?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  de.file_type == Inode::FT_FILE
end

#fs_fileMtime(p) ⇒ Object

Returns Ruby Time object.



137
138
139
140
141
# File 'lib/fs/MiqFS/modules/XFS.rb', line 137

def fs_fileMtime(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.get_inode(de.inode).mTime
end

#fs_fileMtime_obj(fobj) ⇒ Object

Returns a Ruby Time obect.



166
167
168
# File 'lib/fs/MiqFS/modules/XFS.rb', line 166

def fs_fileMtime_obj(fobj)
  fobj.inode.modification_time
end

#fs_fileOpen(p, mode = "r") ⇒ Object

New FileObject instance. NOTE: FileObject must have access to XFS members. This is kind of like a ‘skip this’ thing. XFS methods use stuff owned by MiqFS, so this is necessary.



174
175
176
177
178
# File 'lib/fs/MiqFS/modules/XFS.rb', line 174

def fs_fileOpen(p, mode = "r")
  fobj = FileObject.new(p, self)
  fobj.open(mode)
  fobj
end

#fs_fileRead(fobj, len) ⇒ Object

Returns a Ruby String object.



186
187
188
# File 'lib/fs/MiqFS/modules/XFS.rb', line 186

def fs_fileRead(fobj, len)
  fobj.inode.read(len)
end

#fs_fileSeek(fobj, offset, whence) ⇒ Object

Returns current file position.



181
182
183
# File 'lib/fs/MiqFS/modules/XFS.rb', line 181

def fs_fileSeek(fobj, offset, whence)
  fobj.inode.seek(offset, whence)
end

#fs_fileSize(p) ⇒ Object

Returns size in bytes.



111
112
113
114
115
# File 'lib/fs/MiqFS/modules/XFS.rb', line 111

def fs_fileSize(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.get_inode(de.inode).length
end

#fs_fileSize_obj(fobj) ⇒ Object

In these, fobj is a FileObject.



151
152
153
# File 'lib/fs/MiqFS/modules/XFS.rb', line 151

def fs_fileSize_obj(fobj)
  fobj.inode.length
end

#fs_fileWrite(_fobj, _buf, _len) ⇒ Object



190
191
192
# File 'lib/fs/MiqFS/modules/XFS.rb', line 190

def fs_fileWrite(_fobj, _buf, _len)
  raise "Write functionality is not yet supported on XFS."
end

#fs_freeBytesObject

Returns free space on file system in bytes.



56
57
58
# File 'lib/fs/MiqFS/modules/XFS.rb', line 56

def fs_freeBytes
  @superblock.free_bytes
end

#fs_initObject

File system interface.



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/fs/MiqFS/modules/XFS.rb', line 41

def fs_init
  self.fsType = "XFS"

  # Initialize bs & read root dir.
  @dobj.seek(0, IO::SEEK_SET)
  self.superblock  = Superblock.new(@dobj)
  @fs_id           = superblock.filesystem_id.to_s
  @volName         = superblock.volume_name
  self.rootDir     = Directory.new(superblock, superblock.root_inode)
  self.entry_cache = LruHash.new(DEF_CACHE_SIZE)
  self.dir_cache   = LruHash.new(DEF_CACHE_SIZE)
  self.cache_hits  = 0
end

#fs_isSymLink?(p) ⇒ Boolean

Return true if p is a path to a symbolic link.

Returns:

  • (Boolean)


144
145
146
147
148
# File 'lib/fs/MiqFS/modules/XFS.rb', line 144

def fs_isSymLink?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  de.symlink?
end

#ifs_getDir(p, miqfs = nil) ⇒ Object

Return a Directory object for a path. Raise error if path doesn’t exist.



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/fs/MiqFS/modules/XFS.rb', line 254

def ifs_getDir(p, miqfs = nil)
  # If this is being called from a FileObject instance, then MiqFS owns contained instance members.
  # If this is being called from an XFS module method, then self owns contained instance members.
  miqfs = self if miqfs.nil?

  # Wack leading drive.
  p = unnormalizePath(p)

  # Get an array of directory names, kill off the first (it's always empty).
  names = p.split(/[\\\/]/)
  names.shift

  dir = ifs_getDirR(names, miqfs)
  $log.info("Directory '#{p}' not found") if dir.nil?
  dir
end

#ifs_getDirR(names, miqfs) ⇒ Object

Return Directory recursively for given directory or nil if not exist.



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/fs/MiqFS/modules/XFS.rb', line 272

def ifs_getDirR(names, miqfs)
  return miqfs.rootDir if names.empty?

  # Check for this path in the cache.
  fname = names.join('/')
  if miqfs.dir_cache.key?(fname)
    miqfs.cache_hits += 1
    return miqfs.dir_cache[fname]
  end

  name = names.pop
  pdir = ifs_getDirR(names, miqfs)
  return nil if pdir.nil?

  de = pdir.find_entry(name, Inode::FT_DIRECTORY)
  return nil if de.nil?
  miqfs.entry_cache[fname] = de

  dir = Directory.new(miqfs.superblock, de.inode)
  return nil if dir.nil?

  miqfs.dir_cache[fname] = dir
end

#ifs_getFile(p, miqfs = nil) ⇒ Object

Return a DirectoryEntry for a given file or nil if not exist.



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/fs/MiqFS/modules/XFS.rb', line 205

def ifs_getFile(p, miqfs = nil)
  # If this is being called from a FileObject instance, then MiqFS owns contained instance members.
  # If this is being called from an XFS module method, then self owns contained instance members.
  miqfs = self if miqfs.nil?

  # Preprocess path.
  p = unnormalizePath(p)
  dir, fname = File.split(p)
  # Fix for FB#835: if fil == root then fil needs to be "."
  fname = "." if fname == "/" || fname == "\\"

  # Check for this file in the cache.
  cache_name = "#{dir == '/' ? '' : dir}/#{fname}"
  if miqfs.entry_cache.key?(cache_name)
    miqfs.cache_hits += 1
    return miqfs.entry_cache[cache_name]
  end

  # Look for file in dir, but don't error if it doesn't exist.
  # NOTE: if p is a directory that's ok, find it.
  begin
    directory_object = ifs_getDir(dir, miqfs)
    directory_entry = directory_object.nil? ? nil : directory_object.find_entry(fname)
  rescue RuntimeError
    directory_entry = nil
  end

  miqfs.entry_cache[cache_name] = directory_entry
end

#ifs_putFile(_p, _miqfs = nil) ⇒ Object

Create a directory entry.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/fs/MiqFS/modules/XFS.rb', line 236

def ifs_putFile(_p, _miqfs = nil)
  raise "Write functionality is not yet supported on XFS."
  # If this is being called from a FileObject instance, then MiqFS owns contained instance members.
  # If this is being called from an XFS module method, then self owns contained instance members.
  # miqfs = self if miqfs.nil?

  # Preprocess path.
  # p = unnormalizePath(p)
  # dir, fil = File.split(p)

  # Parent directory must exist.
  # dirObj = ifs_getDir(dir, miqfs)
  # return nil if dir.nil?
  # dirObj.createFile(fil)
end

#unnormalizePath(p) ⇒ Object

Wack leading drive letter & colon.



297
298
299
# File 'lib/fs/MiqFS/modules/XFS.rb', line 297

def unnormalizePath(p)
  p[1] == 58 ? p[2, p.size] : p
end