This pull request contains the XFS filesystem driver for Syslinux.
Due to historical reasons (SGI IRIX's design of disk layouts), the first
sector in the primary AG on XFS filesystems contains the superblock,
which is a problem with BIOSes, since VBRs must be loaded up from the
first sector of the active partition.
Thus, we needed to handle this issue by putting the Syslinux
bootsector hard-coded in the 4th sector (at offset 2048) which is an
unused area in XFS filesystems. The MBR code will know how to load the
Syslinux bootsector from a XFS filesystem by checking the first 4 bytes
in the first sector of the active partition to see it contains a valid
XFS's superblock magic number. If the number matches, then it will load
the bootsector from 4th sector instead.
Since we hard-code the Syslinux bootsector at 0x800 (4th sector) due to
BIOS limitation, then we need to have a XFS filesystem with 4 KiB
filesystem block size. You can also test it with a filesystem block size
larger than 4 KiB but it won't _probably_ work.
Hi Peter,
Please consider pulling it.
Paulo
The following changes since commit 0a0e0e41cad93cd16c323cf16f40264a21eedd6c:
Correct initialization of the cache doubly-linked list (2012-07-19 07:29:55
-0700)
are available in the git repository at:
git://zytor.com/users/pcacjr/syslinux.git xfs-for-hpa
for you to fetch changes up to 75cf6cebf0ffdf75f359528b01fc9039062e7b34:
xfs: Fix the way we check di_mode of an inode (2012-09-02 20:07:20 -0300)
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
----------------------------------------------------------------
Chen Baozi (14):
extlinux: put set_attributes() back to ext2_fat_install_file().
Fix the calculation of the block of the root of the inode B+tree.
Add support for 64-bit filesystem compatible struct inode.
xfs: rework the logic of xfs_get_ino_core()
xfs: Implement dir2_block_find_entry() function.
xfs: Implement xfs_dir2_leaf_find_entry() logic.
xfs: get_dirblks() with count.
xfs: rework xfs_dir2_node_find_entry()
xfs: Add xfs_fmt_btree_find_entry()
xfs: Add full B+tree search support in xfs_dir2_node_find_entry()
xfs: cleanup unused structure
xfs: Rework xfs_dir2_get_right_blk()
xfs: Add XFS_DINODE_FMT_BTREE support in xfs_next_extent()
xfs: Add xfs_readlink()
Paulo Alcantara (46):
EXTLINUX: Initial XFS filesystem support
mbr: Add support for loading VBRs from XFS filesystems
xfs: Initial skeleton for XFS filesystem support
xfs: Implement xfs_fs_init() function
xfs: Add xfs_iget_root() to XFS filesystem ops
xfs: Fix inode lookup in chunks of 64 inodes
xfs: Add xfs_get_agi() function
xfs: Fix inode size attribution
xfs: Add xfs_iget() to filesystem ops
xfs: Fix some inode number conversions
xfs: Remove duplicate variable attribution
xfs: Some bugfixes
xfs: Remove unnecessary check in xfs_iget() function
xfs: Make for-statement declaration more readable
xfs: Fix minor typo
xfs: Add xfs_getfssec() and xfs_next_extent() functions
xfs: Cleanup
xfs: Make sure that the dinode is read with success
xfs: Only call fill_xfs_inode_pvt() if dinode was read
xfs: Cleanup fill_xfs_inode_pvt() function
xfs: Cleanup
xfs: Add xfs_readdir() to filesystem ops
xfs: Remove unnecessary debug message in xfs_getfssec()
xfs: Fix bug in xfs_dir2_leaf_find_entry() function
xfs: Make xfs_da_hashname() function static
xfs: Fix binary search in xfs_dir2_leaf_find_entry() function
xfs: Implement xfs_dir2_leaf_readdir() function
xfs: Use bmbt_irec_get() to get extent information instead
xfs: Use dprintf() for debug messages in xfs_debug()
xfs: Use xfs_debug() for "Entry not found!" message
xfs: Implement xfs_dir2_node_find_entry() function
xfs: Fix memory leaks in xfs_dir2_node_find_entry() function
xfs: Move dir2 functions to another source file
xfs: Remove trailing whitespace in xfs_dir2_isleaf() function
xfs: Move readdir functions to another source file
xfs: Add xfs_fmt_local_find_entry() function
xfs: Add xfs_fmt_local_readdir() function
EXTLINUX: Add sanity check for XFS filesystems
xfs: Implement xfs_readdir_dir2_node() function
xfs: Cleanup xfs_readdir_dir2_leaf() function
xfs: Fix memory leak in xfs_dir2_node_find_entry() function
xfs: Remove some trailing whitespaces
xfs: Cleanup and remove some trailing whitespaces
xfs: Cleanup and remove some trailing whitespaces
xfs: Cleanup previous commit
xfs: Fix the way we check di_mode of an inode
core/fs/xfs/misc.h | 50 +++
core/fs/xfs/xfs.c | 439 ++++++++++++++++++++++++++
core/fs/xfs/xfs.h | 752 ++++++++++++++++++++++++++++++++++++++++++++
core/fs/xfs/xfs_ag.h | 189 +++++++++++
core/fs/xfs/xfs_dinode.c | 61 ++++
core/fs/xfs/xfs_dinode.h | 23 ++
core/fs/xfs/xfs_dir2.c | 759 +++++++++++++++++++++++++++++++++++++++++++++
core/fs/xfs/xfs_dir2.h | 54 ++++
core/fs/xfs/xfs_fs.h | 501 ++++++++++++++++++++++++++++++
core/fs/xfs/xfs_readdir.c | 404 ++++++++++++++++++++++++
core/fs/xfs/xfs_readdir.h | 30 ++
core/fs/xfs/xfs_sb.h | 206 ++++++++++++
core/fs/xfs/xfs_types.h | 135 ++++++++
core/include/fs.h | 6 +-
core/ldlinux.asm | 2 +
extlinux/main.c | 235 +++++++++++---
extlinux/misc.h | 50 +++
extlinux/xfs.h | 25 ++
extlinux/xfs_fs.h | 501 ++++++++++++++++++++++++++++++
extlinux/xfs_sb.h | 476 ++++++++++++++++++++++++++++
extlinux/xfs_types.h | 135 ++++++++
libinstaller/syslxfs.h | 5 +-
mbr/mbr.S | 13 +
23 files changed, 5011 insertions(+), 40 deletions(-)
create mode 100644 core/fs/xfs/misc.h
create mode 100644 core/fs/xfs/xfs.c
create mode 100644 core/fs/xfs/xfs.h
create mode 100644 core/fs/xfs/xfs_ag.h
create mode 100644 core/fs/xfs/xfs_dinode.c
create mode 100644 core/fs/xfs/xfs_dinode.h
create mode 100644 core/fs/xfs/xfs_dir2.c
create mode 100644 core/fs/xfs/xfs_dir2.h
create mode 100644 core/fs/xfs/xfs_fs.h
create mode 100644 core/fs/xfs/xfs_readdir.c
create mode 100644 core/fs/xfs/xfs_readdir.h
create mode 100644 core/fs/xfs/xfs_sb.h
create mode 100644 core/fs/xfs/xfs_types.h
create mode 100644 extlinux/misc.h
create mode 100644 extlinux/xfs.h
create mode 100644 extlinux/xfs_fs.h
create mode 100644 extlinux/xfs_sb.h
create mode 100644 extlinux/xfs_types.h
diff --git a/core/fs/xfs/misc.h b/core/fs/xfs/misc.h
new file mode 100644
index 0000000..7f2f1b3
--- /dev/null
+++ b/core/fs/xfs/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+ return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL)
<< 56) |
+ (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+ (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) << 8) |
+ (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+ return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) <<
24) |
+ (((uint32_t)val & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)val & (uint32_t)0x00ff0000UL) >> 8) |
+ (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+ return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+ (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
new file mode 100644
index 0000000..98d6255
--- /dev/null
+++ b/core/fs/xfs/xfs.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include <ilog2.h>
+#include <klibc/compiler.h>
+#include <ctype.h>
+
+#include "codepage.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+#include "xfs_readdir.h"
+
+static inline int xfs_fmt_local_readdir(struct file *file,
+ struct dirent *dirent, xfs_dinode_t *core)
+{
+ return xfs_readdir_dir2_block(file, dirent, core);
+}
+
+static inline int xfs_fmt_extents_readdir(struct file *file,
+ struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ int retval;
+
+ if (be32_to_cpu(core->di_nextents) <= 1) {
+ /* Single-block Directories */
+ retval = xfs_readdir_dir2_block(file, dirent, core);
+ } else if (xfs_dir2_isleaf(file->fs, core)) {
+ /* Leaf Directory */
+ retval = xfs_readdir_dir2_leaf(file, dirent, core);
+ } else {
+ /* Node Directory */
+ retval = xfs_readdir_dir2_node(file, dirent, core);
+ }
+
+ return retval;
+}
+
+static int xfs_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ xfs_dinode_t *core;
+ struct inode *inode = file->inode;
+ int retval = -1;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino %llx)",
inode->ino);
+ return -1;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL)
+ retval = xfs_fmt_local_readdir(file, dirent, core);
+ else if (core->di_format == XFS_DINODE_FMT_EXTENTS)
+ retval = xfs_fmt_extents_readdir(file, dirent, core);
+
+ return retval;
+}
+
+static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ return generic_getfssec(file, buf, sectors, have_more);
+}
+
+static int xfs_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core = NULL;
+ xfs_bmbt_irec_t rec;
+ block_t bno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ xfs_bmbt_ptr_t *pp;
+ xfs_btree_block_t *blk;
+ uint16_t nextents;
+ block_t nextbno;
+ uint32_t index;
+
+ (void)lstart;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino %llx)",
inode->ino);
+ goto out;
+ }
+
+ /* The data fork contains the file's data extents */
+ if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
+ goto out;
+
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ XFS_PVT(inode)->i_cur_extent++);
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs) >>
SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount << BLOCK_SHIFT(fs)) +
+ SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ index = XFS_PVT(inode)->i_cur_extent++;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >>
BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >>
BLOCK_SHIFT(fs);
+ }
+
+ /* Find the right extent among threaded leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ if (nextents - index > 0) {
+ bmbt_irec_get(&rec, XFS_BMDR_REC_ADDR(blk, index + 1));
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock)
+ >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs)
+ >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount
+ << BLOCK_SHIFT(fs))
+ + SECTOR_SIZE(fs) - 1)
+ >> SECTOR_SHIFT(fs);
+ break;
+ }
+
+ index -= nextents;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
+ }
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static inline struct inode *xfs_fmt_local_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ return xfs_dir2_local_find_entry(dname, parent, core);
+}
+
+static inline struct inode *xfs_fmt_extents_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ struct inode *inode;
+
+ if (be32_to_cpu(core->di_nextents) <= 1) {
+ /* Single-block Directories */
+ inode = xfs_dir2_block_find_entry(dname, parent, core);
+ } else if (xfs_dir2_isleaf(parent->fs, core)) {
+ /* Leaf Directory */
+ inode = xfs_dir2_leaf_find_entry(dname, parent, core);
+ } else {
+ /* Node Directory */
+ inode = xfs_dir2_node_find_entry(dname, parent, core);
+ }
+
+ return inode;
+}
+
+static inline struct inode *xfs_fmt_btree_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ return xfs_dir2_node_find_entry(dname, parent, core);
+}
+
+static struct inode *xfs_iget(const char *dname, struct inode *parent)
+{
+ struct fs_info *fs = parent->fs;
+ xfs_dinode_t *core = NULL;
+ struct inode *inode = NULL;
+
+ xfs_debug("dname %s parent %p parent ino %lu", dname, parent,
parent->ino);
+
+ core = xfs_dinode_get_core(fs, parent->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)",
parent->ino);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ inode = xfs_fmt_local_find_entry(dname, parent, core);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ inode = xfs_fmt_extents_find_entry(dname, parent, core);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ inode = xfs_fmt_btree_find_entry(dname, parent, core);
+ } else {
+ xfs_debug("format %hhu", core->di_format);
+ xfs_debug("TODO: format \"local\" and \"extents\" are
the only "
+ "supported ATM");
+ goto out;
+ }
+
+ if (!inode) {
+ xfs_debug("Entry not found!");
+ goto out;
+ }
+
+ if (inode->mode == DT_REG) {
+ XFS_PVT(inode)->i_offset = 0;
+ XFS_PVT(inode)->i_cur_extent = 0;
+ } else if (inode->mode == DT_DIR) {
+ XFS_PVT(inode)->i_btree_offset = 0;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ }
+
+ return inode;
+
+out:
+ return NULL;
+}
+
+static int xfs_readlink(struct inode *inode, char *buf)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core;
+ int pathlen = -1;
+ xfs_bmbt_irec_t rec;
+ block_t db;
+ char *dir_buf;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)",
inode->ino);
+ goto out;
+ }
+
+ pathlen = be64_to_cpu(core->di_size);
+ if (!pathlen)
+ goto out;
+
+ if (pathlen < 0 || pathlen > MAXPATHLEN) {
+ xfs_error("inode (%llu) bad symlink length (%d)",
+ inode->ino, pathlen);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ memcpy(buf, (char *)&core->di_literal_area[0], pathlen);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+ dir_buf = xfs_dir2_get_dirblks(fs, db, rec.br_blockcount);
+
+ /*
+ * Syslinux only supports filesystem block size larger than or equal to
+ * 4 KiB. Thus, one directory block is far enough to hold the maximum
+ * symbolic link file content, which is only 1024 bytes long.
+ */
+ memcpy(buf, dir_buf, pathlen);
+ free(dir_buf);
+ }
+
+out:
+ return pathlen;
+}
+
+static struct inode *xfs_iget_root(struct fs_info *fs)
+{
+ xfs_dinode_t *core = NULL;
+ struct inode *inode = xfs_new_inode(fs);
+
+ xfs_debug("Looking for the root inode...");
+
+ core = xfs_dinode_get_core(fs, XFS_INFO(fs)->rootino);
+ if (!core) {
+ xfs_error("Inode core's magic number does not match!");
+ xfs_debug("magic number 0x%04x", be16_to_cpu(core->di_magic));
+ goto out;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, XFS_INFO(fs)->rootino);
+
+ xfs_debug("Root inode has been found!");
+
+ if ((be16_to_cpu(core->di_mode) & S_IFMT) != S_IFDIR) {
+ xfs_error("root inode is not a directory ?! No makes sense...");
+ goto out;
+ }
+
+ inode->ino = XFS_INFO(fs)->rootino;
+ inode->mode = DT_DIR;
+ inode->size = be64_to_cpu(core->di_size);
+
+ return inode;
+
+out:
+ free(inode);
+
+ return NULL;
+}
+
+static inline int xfs_read_superblock(struct fs_info *fs, xfs_sb_t *sb)
+{
+ struct disk *disk = fs->fs_dev->disk;
+
+ if (!disk->rdwr_sectors(disk, sb, XFS_SB_DADDR, 1, false))
+ return -1;
+
+ return 0;
+}
+
+static struct xfs_fs_info *xfs_new_sb_info(xfs_sb_t *sb)
+{
+ struct xfs_fs_info *info;
+
+ info = malloc(sizeof *info);
+ if (!info)
+ malloc_error("xfs_fs_info structure");
+
+ info->blocksize = be32_to_cpu(sb->sb_blocksize);
+ info->block_shift = sb->sb_blocklog;
+ info->dirblksize = 1 << (sb->sb_blocklog +
sb->sb_dirblklog);
+ info->dirblklog = sb->sb_dirblklog;
+ info->inopb_shift = sb->sb_inopblog;
+ info->agblk_shift = sb->sb_agblklog;
+ info->rootino = be64_to_cpu(sb->sb_rootino);
+ info->agblocks = be32_to_cpu(sb->sb_agblocks);
+ info->agblocks_shift = sb->sb_agblklog;
+ info->agcount = be32_to_cpu(sb->sb_agcount);
+ info->inodesize = be16_to_cpu(sb->sb_inodesize);
+ info->inode_shift = sb->sb_inodelog;
+
+ return info;
+}
+
+static int xfs_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ xfs_sb_t sb;
+ struct xfs_fs_info *info;
+
+ xfs_debug("fs %p", fs);
+
+ SECTOR_SHIFT(fs) = disk->sector_shift;
+ SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs);
+
+ if (xfs_read_superblock(fs, &sb)) {
+ xfs_error("Superblock read failed");
+ goto out;
+ }
+
+ if (!xfs_is_valid_magicnum(&sb)) {
+ xfs_error("Invalid superblock");
+ goto out;
+ }
+
+ xfs_debug("magicnum 0x%lX", be32_to_cpu(sb.sb_magicnum));
+
+ info = xfs_new_sb_info(&sb);
+ if (!info) {
+ xfs_error("Failed to fill in filesystem-specific info structure");
+ goto out;
+ }
+
+ fs->fs_info = info;
+
+ xfs_debug("block_shift %u blocksize 0x%lX (%lu)",
info->block_shift,
+ info->blocksize, info->blocksize);
+
+ xfs_debug("rootino 0x%llX (%llu)", info->rootino,
info->rootino);
+
+ BLOCK_SHIFT(fs) = info->block_shift;
+ BLOCK_SIZE(fs) = info->blocksize;
+
+ cache_init(fs->fs_dev, BLOCK_SHIFT(fs));
+
+ XFS_INFO(fs)->dirleafblk = xfs_dir2_db_to_da(fs,
XFS_DIR2_LEAF_FIRSTDB(fs));
+
+ return BLOCK_SHIFT(fs);
+
+out:
+ return -1;
+}
+
+const struct fs_ops xfs_fs_ops = {
+ .fs_name = "xfs",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = xfs_fs_init,
+ .iget_root = xfs_iget_root,
+ .searchdir = NULL,
+ .getfssec = xfs_getfssec,
+ .load_config = generic_load_config,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .readdir = xfs_readdir,
+ .iget = xfs_iget,
+ .next_extent = xfs_next_extent,
+ .readlink = xfs_readlink,
+};
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
new file mode 100644
index 0000000..da57221
--- /dev/null
+++ b/core/fs/xfs/xfs.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * Some parts borrowed from Linux kernel tree (linux/fs/xfs):
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#include <disk.h>
+#include <fs.h>
+#include <dprintf.h>
+
+#include "xfs_types.h"
+#include "xfs_ag.h"
+
+#define xfs_error(fmt, args...) \
+ printf("xfs: " fmt "\n", ## args);
+
+#define xfs_debug(fmt, args...) \
+ dprintf("%s: " fmt "\n", __func__, ## args);
+
+struct xfs_fs_info;
+
+#define XFS_INFO(fs) ((struct xfs_fs_info *)((fs)->fs_info))
+#define XFS_PVT(ino) ((struct xfs_inode *)((ino)->pvt))
+
+#define XFS_INO_MASK(k) (uint32_t)((1ULL << (k)) - 1)
+#define XFS_INO_OFFSET_BITS(fs) (fs)->inopb_shift
+#define XFS_INO_AGINO_BITS(fs) \
+ (XFS_INFO((fs))->inopb_shift + XFS_INFO((fs))->agblk_shift)
+
+#define XFS_INO_TO_AGINO(fs, i) \
+ ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(fs)))
+
+#define XFS_INO_TO_AGNO(fs, ino) \
+ ((xfs_agnumber_t)((ino) >> (XFS_INFO((fs))->inopb_shift + \
+ XFS_INFO((fs))->agblk_shift)))
+
+#define XFS_INO_TO_OFFSET(fs, i) \
+ ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(fs)))
+
+#define XFS_AGNO_TO_FSB(fs, agno) \
+ ((block_t)((agno) << XFS_INFO((fs))->agblocks_shift))
+
+#define XFS_AGI_OFFS(fs, mp) \
+ ((xfs_agi_t *)((uint8_t *)(mp) + 2 * SECTOR_SIZE((fs))))
+
+#define XFS_GET_DIR_INO4(di) \
+ (((uint32_t)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2]
<< 8) | \
+ ((di).i[3]))
+
+#define XFS_DI_HI(di) \
+ (((uint32_t)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
+
+#define XFS_DI_LO(di) \
+ (((uint32_t)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6]
<< 8) | \
+ ((di).i[7]))
+
+#define XFS_GET_DIR_INO8(di) \
+ (((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
+ ((xfs_ino_t)XFS_DI_HI(di) << 32))
+
+#define XFS_FSB_TO_AGNO(fs, fsbno) \
+ ((xfs_agnumber_t)((fsbno) >> XFS_INFO((fs))->agblk_shift))
+#define XFS_FSB_TO_AGBNO(fs, fsbno) \
+ ((xfs_agblock_t)((fsbno) & (uint32_t)((1ULL << \
+ XFS_INFO((fs))->agblk_shift) - 1)))
+
+#define agblock_to_bytes(fs, x) \
+ ((uint64_t)(x) << BLOCK_SHIFT((fs)))
+#define agino_to_bytes(fs, x) \
+ ((uint64_t)(x) << XFS_INFO((fs))->inode_shift)
+#define agnumber_to_bytes(fs, x) \
+ agblock_to_bytes(fs, (uint64_t)(x) * XFS_INFO((fs))->agblocks)
+#define fsblock_to_bytes(fs,x) \
+ (agnumber_to_bytes(fs, XFS_FSB_TO_AGNO(fs, (x))) + \
+ agblock_to_bytes(fs, XFS_FSB_TO_AGBNO(fs, (x))))
+#define ino_to_bytes(fs, x) \
+ (agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, (x))) + \
+ agino_to_bytes(fs, XFS_INO_TO_AGINO(fs, (x))))
+
+/* Superblock's LBA */
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */
+
+/* Magic numbers */
+#define XFS_AGI_MAGIC "XAGI"
+#define XFS_IBT_MAGIC "IABT"
+#define XFS_DINODE_MAGIC "IN"
+
+#define XFS_DIR2_BLOCK_MAGIC 0x58443242U /* XD2B: single block dirs */
+#define XFS_DIR2_DATA_MAGIC 0x58443244U /* XD2D: multiblock dirs */
+#define XFS_DIR2_FREE_MAGIC 0x58443246U /* XD2F: free index blocks */
+
+#define XFS_DIR2_NULL_DATAPTR ((uint32_t)0)
+
+/* File types and modes */
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define MAXPATHLEN 1024
+/*
+ * NOTE: The fields in the superblock are stored in big-endian format on disk.
+ */
+typedef struct xfs_sb {
+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ uint16_t sb_sectsize; /* volume sector size, bytes */
+ uint16_t sb_inodesize; /* inode size, bytes */
+ uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ uint8_t sb_rextslog; /* log2 of sb_rextents */
+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ uint64_t sb_icount; /* allocated inodes */
+ uint64_t sb_ifree; /* free inodes */
+ uint64_t sb_fdblocks; /* free data blocks */
+ uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ uint16_t sb_qflags; /* quota flags */
+ uint8_t sb_flags; /* misc. flags */
+ uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ uint32_t sb_unit; /* stripe or raid unit */
+ uint32_t sb_width; /* stripe or raid width */
+ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ uint8_t sb_logsectlog; /* log2 of the log sector size */
+ uint16_t sb_logsectsize; /* sector size for the log, bytes */
+ uint32_t sb_logsunit; /* stripe unit size for the log */
+ uint32_t sb_features2; /* additional feature bits */
+
+ /*
+ * bad features2 field as a result of failing to pad the sb
+ * structure to 64 bits. Some machines will be using this field
+ * for features2 bits. Easiest just to mark it bad and not use
+ * it for anything else.
+ */
+ uint32_t sb_bad_features2;
+ uint8_t pad[304]; /* must be padded to a sector boundary */
+} __attribute__((__packed__)) xfs_sb_t;
+
+/* In-memory structure that stores filesystem-specific information.
+ * The information stored is basically retrieved from the XFS superblock
+ * to be used statically around the driver.
+ */
+struct xfs_fs_info {
+ uint32_t blocksize; /* Filesystem block size */
+ uint8_t block_shift; /* Filesystem block size in bits */
+ uint32_t dirblksize;
+ uint8_t dirblklog;
+ uint8_t inopb_shift;
+ uint8_t agblk_shift;
+ uint32_t dirleafblk;
+
+ /* AG number bits (MSB of the inode number) */
+ uint8_t ag_number_ino_shift;
+
+ xfs_ino_t rootino; /* Root inode number for the filesystem */
+ xfs_agblock_t agblocks; /* Size of each AG in blocks */
+ uint8_t agblocks_shift; /* agblocks in bits */
+ xfs_agnumber_t agcount; /* Number of AGs in the filesytem */
+ uint16_t inodesize; /* Size of the inode in bytes */
+ uint8_t inode_shift; /* Inode size in bits */
+} __attribute__((__packed__));
+
+typedef struct xfs_agi {
+ /*
+ * Common allocation group header information
+ */
+ uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */
+ uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */
+ uint32_t agi_seqno; /* sequence # starting from 0 */
+ uint32_t agi_length; /* size in blocks of a.g. */
+ /*
+ * Inode information
+ * Inodes are mapped by interpreting the inode number, so no
+ * mapping data is needed here.
+ */
+ uint32_t agi_count; /* count of allocated inodes */
+ uint32_t agi_root; /* root of inode btree */
+ uint32_t agi_level; /* levels in inode btree */
+ uint32_t agi_freecount; /* number of free inodes */
+ uint32_t agi_newino; /* new inode just allocated */
+ uint32_t agi_dirino; /* last directory inode chunk */
+ /*
+ * Hash table of inodes which have been unlinked but are
+ * still being referenced.
+ */
+ uint32_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
+} __attribute__((__packed__)) xfs_agi_t;
+
+/*
+ * Bmap btree record and extent descriptor.
+ * l0:63 is an extent flag (value 1 indicates non-normal).
+ * l0:9-62 are startoff.
+ * l0:0-8 and l1:21-63 are startblock.
+ * l1:0-20 are blockcount.
+ */
+typedef struct xfs_bmbt_rec {
+ uint64_t l0;
+ uint64_t l1;
+} __attribute__((__packed__)) xfs_bmbt_rec_t;
+
+typedef xfs_bmbt_rec_t xfs_bmdr_rec_t;
+
+/*
+ * Possible extent states.
+ */
+typedef enum {
+ XFS_EXT_NORM,
+ XFS_EXT_UNWRITTEN,
+ XFS_EXT_DMAPI_OFFLINE,
+ XFS_EXT_INVALID,
+} xfs_exntst_t;
+
+typedef struct xfs_bmbt_irec
+{
+ xfs_fileoff_t br_startoff; /* starting file offset */
+ xfs_fsblock_t br_startblock; /* starting block number */
+ xfs_filblks_t br_blockcount; /* number of blocks */
+ xfs_exntst_t br_state; /* extent state */
+} __attribute__((__packed__)) xfs_bmbt_irec_t;
+
+static inline void bmbt_irec_get(xfs_bmbt_irec_t *dest,
+ const xfs_bmbt_rec_t *src)
+{
+ uint64_t l0, l1;
+
+ l0 = be64_to_cpu(src->l0);
+ l1 = be64_to_cpu(src->l1);
+
+ dest->br_startoff = ((xfs_fileoff_t)l0 & 0x7ffffffffffffe00ULL)
>> 9;
+ dest->br_startblock = (((xfs_fsblock_t)l0 & 0x00000000000001ffULL)
<< 43) |
+ (((xfs_fsblock_t)l1) >> 21);
+ dest->br_blockcount = (xfs_filblks_t)(l1 & 0x00000000001fffffULL);
+ dest->br_state = (l0 & 0x8000000000000000ULL) ?
+ XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
+}
+
+typedef struct xfs_timestamp {
+ int32_t t_sec;
+ int32_t t_nsec;
+} __attribute__((__packed__)) xfs_timestamp_t;
+
+/*
+ * Fork identifiers.
+ */
+#define XFS_DATA_FORK 0
+#define xFS_ATTR_FORK 1
+
+typedef enum xfs_dinode_fmt {
+ XFS_DINODE_FMT_DEV,
+ XFS_DINODE_FMT_LOCAL,
+ XFS_DINODE_FMT_EXTENTS,
+ XFS_DINODE_FMT_BTREE,
+ XFS_DINODE_FMT_UUID,
+} xfs_dinode_fmt_t;
+
+typedef struct xfs_dinode {
+ uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
+ uint16_t di_mode; /* mode and type of file */
+ uint8_t di_version; /* inode version */
+ uint8_t di_format; /* format of di_c data */
+ uint16_t di_onlink; /* old number of links to file */
+ uint32_t di_uid; /* owner's user id */
+ uint32_t di_gid; /* owner's group id */
+ uint32_t di_nlink; /* number of links to file */
+ uint16_t di_projid_lo; /* lower part of owner's project id */
+ uint16_t di_projid_hi; /* higher part owner's project id */
+ uint8_t di_pad[6]; /* unused, zeroed space */
+ uint16_t di_flushiter; /* incremented on flush */
+ xfs_timestamp_t di_atime; /* time last accessed */
+ xfs_timestamp_t di_mtime; /* time last modified */
+ xfs_timestamp_t di_ctime; /* time created/inode modified */
+ uint64_t di_size; /* number of bytes in file */
+ uint64_t di_nblocks; /* # of direct & btree blocks used */
+ uint32_t di_extsize; /* basic/minimum extent size for file */
+ uint32_t di_nextents; /* number of extents in data fork */
+ uint16_t di_anextents; /* number of extents in attribute fork*/
+ uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
+ int8_t di_aformat; /* format of attr fork's data */
+ uint32_t di_dmevmask; /* DMIG event mask */
+ uint16_t di_dmstate; /* DMIG state info */
+ uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
+ uint32_t di_gen; /* generation number */
+
+ /* di_next_unlinked is the only non-core field in the old dinode */
+ uint32_t di_next_unlinked;/* agi unlinked list ptr */
+ uint8_t di_literal_area[1];
+} __attribute__((packed)) xfs_dinode_t;
+
+/*
+ * Inode size for given fs.
+ */
+#define XFS_LITINO(fs) \
+ ((int)((XFS_INFO(fs)->inodesize) - sizeof(struct xfs_dinode) - 1))
+
+#define XFS_BROOT_SIZE_ADJ \
+ (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
+
+/*
+ * Inode data & attribute fork sizes, per inode.
+ */
+#define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0)
+#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3))
+
+#define XFS_DFORK_DSIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_DFORK_BOFF(dip) : \
+ XFS_LITINO(fs))
+#define XFS_DFORK_ASIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \
+ 0)
+#define XFS_DFORK_SIZE(dip, fs, w) \
+ ((w) == XFS_DATA_FORK ? \
+ XFS_DFORK_DSIZE(dip, fs) : \
+ XFS_DFORK_ASIZE(dip, fs))
+
+struct xfs_inode {
+ xfs_agblock_t i_agblock;
+ block_t i_ino_blk;
+ uint64_t i_block_offset;
+ uint64_t i_offset;
+ uint32_t i_cur_extent;
+ uint32_t i_btree_offset;
+ uint16_t i_leaf_ent_offset;
+};
+
+typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t;
+typedef struct { uint8_t i[4]; } __attribute__((__packed__)) xfs_dir2_ino4_t;
+
+typedef union {
+ xfs_dir2_ino8_t i8;
+ xfs_dir2_ino4_t i4;
+} __attribute__((__packed__)) xfs_dir2_inou_t;
+
+typedef struct { uint8_t i[2]; } __attribute__((__packed__)) xfs_dir2_sf_off_t;
+
+typedef struct xfs_dir2_sf_hdr {
+ uint8_t count; /* count of entries */
+ uint8_t i8count; /* count of 8-byte inode #s */
+ xfs_dir2_inou_t parent; /* parent dir inode number */
+} __attribute__((__packed__)) xfs_dir2_sf_hdr_t;
+
+typedef struct xfs_dir2_sf_entry {
+ uint8_t namelen; /* actual name length */
+ xfs_dir2_sf_off_t offset; /* saved offset */
+ uint8_t name[1]; /* name, variable size */
+ xfs_dir2_inou_t inumber; /* inode number, var. offset */
+} __attribute__((__packed__)) xfs_dir2_sf_entry_t;
+
+typedef struct xfs_dir2_sf {
+ xfs_dir2_sf_hdr_t hdr; /* shortform header */
+ xfs_dir2_sf_entry_t list[1]; /* shortform entries */
+} __attribute__((__packed__)) xfs_dir2_sf_t;
+
+typedef xfs_ino_t xfs_intino_t;
+
+static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
+ xfs_dir2_inou_t *from)
+{
+ return ((sfp)->hdr.i8count == 0 ? \
+ (xfs_intino_t)XFS_GET_DIR_INO4((from)->i4) : \
+ (xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
+}
+
+/*
+ * DIR2 Data block structures.
+ *
+ * A pure data block looks like the following drawing on disk:
+ *
+ * +-------------------------------------------------+
+ * | xfs_dir2_data_hdr_t |
+ * +-------------------------------------------------+
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | ... |
+ * +-------------------------------------------------+
+ * | unused space |
+ * +-------------------------------------------------+
+ *
+ * As all the entries are variable size structure the accessors below should
+ * be used to iterate over them.
+ *
+ * In addition to the pure data blocks for the data and node formats.
+ * most structures are also used for the combined data/freespace
"block"
+ * format below.
+ */
+#define XFS_DIR2_DATA_ALIGN_LOG 3
+#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG)
+#define XFS_DIR2_DATA_FREE_TAG 0xffff
+#define XFS_DIR2_DATA_FD_COUNT 3
+
+/*
+ * Directory address space divided into sections.
+ * spaces separated by 32GB.
+ */
+#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
+
+typedef struct xfs_dir2_data_free {
+ uint16_t offset;
+ uint16_t length;
+} __attribute__((__packed__)) xfs_dir2_data_free_t;
+
+typedef struct xfs_dir2_data_hdr {
+ uint32_t magic;
+ xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
+} __attribute__((__packed__)) xfs_dir2_data_hdr_t;
+
+typedef struct xfs_dir2_data_entry {
+ uint64_t inumber; /* inode number */
+ uint8_t namelen; /* name length */
+ uint8_t name[]; /* name types, no null */
+ /* uint16_t tag; */ /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_entry_t;
+
+typedef struct xfs_dir2_data_unused {
+ uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
+ uint16_t length; /* total free length */
+ /* variable offset */
+ /* uint16_t tag; */ /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_unused_t;
+
+/**
+ * rol32 - rotate a 32-bit value left
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline uint32_t rol32(uint32_t word, signed int shift)
+{
+ return (word << shift) | (word >> (32 - shift));
+}
+
+#define roundup(x, y) ( \
+{ \
+ const typeof(y) __y = y; \
+ (((x) + (__y - 1)) / __y) * __y; \
+} \
+)
+
+static inline int xfs_dir2_data_entsize(int n)
+{
+ return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
+ (unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN);
+}
+
+static inline uint16_t *
+xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
+{
+ return (uint16_t *)((char *)dep +
+ xfs_dir2_data_entsize(dep->namelen) - sizeof(uint16_t));
+}
+
+static inline uint16_t *
+xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
+{
+ return (uint16_t *)((char *)dup +
+ be16_to_cpu(dup->length) - sizeof(uint16_t));
+}
+
+typedef struct xfs_dir2_block_tail {
+ uint32_t count; /* count of leaf entries */
+ uint32_t stale; /* count of stale lf entries */
+} __attribute__((__packed__)) xfs_dir2_block_tail_t;
+
+static inline struct xfs_dir2_block_tail *
+xfs_dir2_block_tail_p(struct xfs_fs_info *fs_info, struct xfs_dir2_data_hdr
*hdr)
+{
+ return ((struct xfs_dir2_block_tail *)
+ ((char *)hdr + fs_info->dirblksize)) - 1;
+}
+
+static inline uint32_t
+xfs_dir2_db_to_da(struct fs_info *fs, uint32_t db)
+{
+ return db << XFS_INFO(fs)->dirblklog;
+}
+
+static inline int64_t
+xfs_dir2_dataptr_to_byte(uint32_t dp)
+{
+ return (int64_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
+}
+
+static inline uint32_t
+xfs_dir2_byte_to_db(struct fs_info *fs, int64_t by)
+{
+ return (uint32_t)
+ (by >> (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog));
+}
+
+static inline uint32_t
+xfs_dir2_dataptr_to_db(struct fs_info *fs, uint32_t dp)
+{
+ return xfs_dir2_byte_to_db(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+static inline unsigned int
+xfs_dir2_byte_to_off(struct fs_info *fs, int64_t by)
+{
+ return (unsigned int)(by &
+ (( 1 << (XFS_INFO(fs)->block_shift +
XFS_INFO(fs)->dirblklog)) - 1));
+}
+
+static inline unsigned int
+xfs_dir2_dataptr_to_off(struct fs_info *fs, uint32_t dp)
+{
+ return xfs_dir2_byte_to_off(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+#define XFS_DIR2_LEAF_SPACE 1
+#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
+#define XFS_DIR2_LEAF_FIRSTDB(fs) \
+ xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)
+
+typedef struct xfs_da_blkinfo {
+ uint32_t forw;
+ uint32_t back;
+ uint16_t magic;
+ uint16_t pad;
+} __attribute__((__packed__)) xfs_da_blkinfo_t;
+
+typedef struct xfs_dir2_leaf_hdr {
+ xfs_da_blkinfo_t info;
+ uint16_t count;
+ uint16_t stale;
+} __attribute__((__packed__)) xfs_dir2_leaf_hdr_t;
+
+typedef struct xfs_dir2_leaf_entry {
+ uint32_t hashval; /* hash value of name */
+ uint32_t address; /* address of data entry */
+} __attribute__((__packed__)) xfs_dir2_leaf_entry_t;
+
+typedef struct xfs_dir2_leaf {
+ xfs_dir2_leaf_hdr_t hdr; /* leaf header */
+ xfs_dir2_leaf_entry_t ents[]; /* entries */
+} __attribute__((__packed__)) xfs_dir2_leaf_t;
+
+#define XFS_DA_NODE_MAGIC 0xfebeU /* magic number: non-leaf blocks */
+#define XFS_ATTR_LEAF_MAGIC 0xfbeeU /* magic number: attribute leaf blks */
+#define XFS_DIR2_LEAF1_MAGIC 0xd2f1U /* magic number: v2 dirlf single blks */
+#define XFS_DIR2_LEAFN_MAGIC 0xd2ffU /* magic number: V2 dirlf multi blks */
+
+typedef struct xfs_da_intnode {
+ struct xfs_da_node_hdr { /* constant-structure header block */
+ xfs_da_blkinfo_t info; /* block type, links, etc. */
+ uint16_t count; /* count of active entries */
+ uint16_t level; /* level above leaves (leaf == 0) */
+ } hdr;
+ struct xfs_da_node_entry {
+ uint32_t hashval; /* hash value for this descendant */
+ uint32_t before; /* Btree block before this key */
+ } btree[1];
+} __attribute__((__packed__)) xfs_da_intnode_t;
+
+typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
+typedef struct xfs_da_node_entry xfs_da_node_entry_t;
+
+static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
+{
+ return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;
+}
+
+static inline bool xfs_is_valid_agi(xfs_agi_t *agi)
+{
+ return agi->agi_magicnum == *(uint32_t *)XFS_AGI_MAGIC;
+}
+
+static inline struct inode *xfs_new_inode(struct fs_info *fs)
+{
+ struct inode *inode;
+
+ inode = alloc_inode(fs, 0, sizeof(struct xfs_inode));
+ if (!inode)
+ malloc_error("xfs_inode structure");
+
+ return inode;
+}
+
+static inline void fill_xfs_inode_pvt(struct fs_info *fs, struct inode *inode,
+ xfs_ino_t ino)
+{
+ XFS_PVT(inode)->i_agblock + agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs,
ino)) >> BLOCK_SHIFT(fs);
+ XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >>
BLOCK_SHIFT(fs);
+ XFS_PVT(inode)->i_block_offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino)
<<
+ XFS_INFO(fs)->inode_shift;
+}
+
+/*
+ * Generic btree header.
+ *
+ * This is a combination of the actual format used on disk for short and long
+ * format btrees. The first three fields are shared by both format, but
+ * the pointers are different and should be used with care.
+ *
+ * To get the size of the actual short or long form headers please use
+ * the size macros belows. Never use sizeof(xfs_btree_block);
+ */
+typedef struct xfs_btree_block {
+ uint32_t bb_magic; /* magic number for block type */
+ uint16_t bb_level; /* 0 is a leaf */
+ uint16_t bb_numrecs; /* current # of data records */
+ union {
+ struct {
+ uint32_t bb_leftsib;
+ uint32_t bb_rightsib;
+ } s; /* short form pointers */
+ struct {
+ uint64_t bb_leftsib;
+ uint64_t bb_rightsib;
+ } l; /* long form pointers */
+ } bb_u; /* rest */
+} xfs_btree_block_t;
+
+#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
+#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
+
+/*
+ * Bmap root header, on-disk form only.
+ */
+typedef struct xfs_bmdr_block {
+ uint16_t bb_level; /* 0 is a leaf */
+ uint16_t bb_numrecs; /* current # of data records */
+} xfs_bmdr_block_t;
+
+/*
+ * Key structure for non-leaf levels of the tree.
+ */
+typedef struct xfs_bmbt_key {
+ uint64_t br_startoff; /* starting file offset */
+} xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+/* btree pointer type */
+typedef uint64_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
+
+/*
+ * Btree block header size depends on a superblock flag.
+ *
+ * (not quite yet, but soon)
+ */
+#define XFS_BMBT_BLOCK_LEN(fs) XFS_BTREE_LBLOCK_LEN
+
+#define XFS_BMBT_REC_ADDR(fs, block, index) \
+ ((xfs_bmbt_rec_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ ((index) - 1) * sizeof(xfs_bmbt_rec_t)))
+
+#define XFS_BMBT_KEY_ADDR(fs, block, index) \
+ ((xfs_bmbt_key_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ ((index) - 1) * sizeof(xfs_bmbt_key_t)))
+
+#define XFS_BMBT_PTR_ADDR(fs, block, index, maxrecs) \
+ ((xfs_bmbt_ptr_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ (maxrecs) * sizeof(xfs_bmbt_key_t) + \
+ ((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
+
+#define XFS_BMDR_REC_ADDR(block, index) \
+ ((xfs_bmdr_rec_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ ((index) - 1) * sizeof(xfs_bmdr_rec_t)))
+
+#define XFS_BMDR_KEY_ADDR(block, index) \
+ ((xfs_bmdr_key_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ ((index) - 1) * sizeof(xfs_bmdr_key_t)))
+
+#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
+ ((xfs_bmdr_ptr_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ (maxrecs) * sizeof(xfs_bmdr_key_t) + \
+ ((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
+
+/*
+ * Calculate number of records in a bmap btree inode root.
+ */
+static inline int
+xfs_bmdr_maxrecs(int blocklen, int leaf)
+{
+ blocklen -= sizeof(xfs_bmdr_block_t);
+
+ if (leaf)
+ return blocklen / sizeof(xfs_bmdr_rec_t);
+
+ return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
+}
+
+#endif /* XFS_H_ */
diff --git a/core/fs/xfs/xfs_ag.h b/core/fs/xfs/xfs_ag.h
new file mode 100644
index 0000000..a2988b1
--- /dev/null
+++ b/core/fs/xfs/xfs_ag.h
@@ -0,0 +1,189 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_AG_H_
+#define XFS_AG_H_
+
+#include "xfs_types.h"
+
+/*
+ * Allocation group header
+ * This is divided into three structures, placed in sequential 512-byte
+ * buffers after a copy of the superblock (also in a 512-byte buffer).
+ */
+
+typedef uint32_t xfs_agino_t;
+
+struct xfs_buf;
+struct xfs_mount;
+struct xfs_trans;
+
+#define XFS_AGF_MAGIC "XAGF"
+#define XFS_AGF_VERSION 1
+#define XFS_AGI_VERSION 1
+
+#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION)
+#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION)
+
+/*
+ * Btree number 0 is bno, 1 is cnt. This value gives the size of the
+ * arrays below.
+ */
+#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1)
+
+/*
+ * The second word of agf_levels in the first a.g. overlaps the EFS
+ * superblock's magic number. Since the magic numbers valid for EFS
+ * are > 64k, our value cannot be confused for an EFS superblock's.
+ */
+
+typedef struct xfs_agf {
+ /*
+ * Common allocation group header information
+ */
+ uint32_t agf_magicnum; /* magic number == XFS_AGF_MAGIC */
+ uint32_t agf_versionnum; /* header version == XFS_AGF_VERSION */
+ uint32_t agf_seqno; /* sequence # starting from 0 */
+ uint32_t agf_length; /* size in blocks of a.g. */
+ /*
+ * Freespace information
+ */
+ uint32_t agf_roots[XFS_BTNUM_AGF]; /* root blocks */
+ uint32_t agf_spare0; /* spare field */
+ uint32_t agf_levels[XFS_BTNUM_AGF]; /* btree levels */
+ uint32_t agf_spare1; /* spare field */
+ uint32_t agf_flfirst; /* first freelist block's index */
+ uint32_t agf_fllast; /* last freelist block's index */
+ uint32_t agf_flcount; /* count of blocks in freelist */
+ uint32_t agf_freeblks; /* total free blocks */
+ uint32_t agf_longest; /* longest free space */
+ uint32_t agf_btreeblks; /* # of blocks held in AGF btrees */
+} xfs_agf_t;
+
+#define XFS_AGF_MAGICNUM 0x00000001
+#define XFS_AGF_VERSIONNUM 0x00000002
+#define XFS_AGF_SEQNO 0x00000004
+#define XFS_AGF_LENGTH 0x00000008
+#define XFS_AGF_ROOTS 0x00000010
+#define XFS_AGF_LEVELS 0x00000020
+#define XFS_AGF_FLFIRST 0x00000040
+#define XFS_AGF_FLLAST 0x00000080
+#define XFS_AGF_FLCOUNT 0x00000100
+#define XFS_AGF_FREEBLKS 0x00000200
+#define XFS_AGF_LONGEST 0x00000400
+#define XFS_AGF_BTREEBLKS 0x00000800
+#define XFS_AGF_NUM_BITS 12
+#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
+
+#define XFS_AGF_FLAGS \
+ { XFS_AGF_MAGICNUM, "MAGICNUM" }, \
+ { XFS_AGF_VERSIONNUM, "VERSIONNUM" }, \
+ { XFS_AGF_SEQNO, "SEQNO" }, \
+ { XFS_AGF_LENGTH, "LENGTH" }, \
+ { XFS_AGF_ROOTS, "ROOTS" }, \
+ { XFS_AGF_LEVELS, "LEVELS" }, \
+ { XFS_AGF_FLFIRST, "FLFIRST" }, \
+ { XFS_AGF_FLLAST, "FLLAST" }, \
+ { XFS_AGF_FLCOUNT, "FLCOUNT" }, \
+ { XFS_AGF_FREEBLKS, "FREEBLKS" }, \
+ { XFS_AGF_LONGEST, "LONGEST" }, \
+ { XFS_AGF_BTREEBLKS, "BTREEBLKS" }
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
+#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
+#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)((bp)->b_addr))
+
+extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
+
+/*
+ * Size of the unlinked inode hash table in the agi.
+ */
+#define XFS_AGI_UNLINKED_BUCKETS 64
+
+#define XFS_AGI_MAGICNUM 0x00000001
+#define XFS_AGI_VERSIONNUM 0x00000002
+#define XFS_AGI_SEQNO 0x00000004
+#define XFS_AGI_LENGTH 0x00000008
+#define XFS_AGI_COUNT 0x00000010
+#define XFS_AGI_ROOT 0x00000020
+#define XFS_AGI_LEVEL 0x00000040
+#define XFS_AGI_FREECOUNT 0x00000080
+#define XFS_AGI_NEWINO 0x00000100
+#define XFS_AGI_DIRINO 0x00000200
+#define XFS_AGI_UNLINKED 0x00000400
+#define XFS_AGI_NUM_BITS 11
+#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1)
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
+#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
+#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)((bp)->b_addr))
+
+extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, struct xfs_buf **bpp);
+
+/*
+ * The third a.g. block contains the a.g. freelist, an array
+ * of block pointers to blocks owned by the allocation btree code.
+ */
+#define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
+#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
+#define XFS_AGFL_SIZE(mp) ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
+#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)((bp)->b_addr))
+
+typedef struct xfs_agfl {
+ uint32_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
+} xfs_agfl_t;
+
+/*
+ * tags for inode radix tree
+ */
+#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
+ in xfs_inode_ag_iterator */
+#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
+
+#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
+#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \
+ (MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + MIN(cl + 1, XFS_AG_MAXLEVELS(mp)))
+#define XFS_MIN_FREELIST(a,mp) \
+ (XFS_MIN_FREELIST_RAW( \
+ be32_to_cpu((a)->agf_levels[XFS_BTNUM_BNOi]), \
+ be32_to_cpu((a)->agf_levels[XFS_BTNUM_CNTi]), mp))
+#define XFS_MIN_FREELIST_PAG(pag,mp) \
+ (XFS_MIN_FREELIST_RAW( \
+ (unsigned int)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
+ (unsigned int)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
+
+/*
+ * For checking for bad ranges of xfs_daddr_t's, covering multiple
+ * allocation groups or a single xfs_daddr_t that's a superblock copy.
+ */
+#define XFS_AG_CHECK_DADDR(mp,d,len) \
+ ((len) == 1 ? \
+ ASSERT((d) == XFS_SB_DADDR || \
+ xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \
+ ASSERT(xfs_daddr_to_agno(mp, d) == \
+ xfs_daddr_to_agno(mp, (d) + (len) - 1)))
+
+#endif /* XFS_AG_H_ */
diff --git a/core/fs/xfs/xfs_dinode.c b/core/fs/xfs/xfs_dinode.c
new file mode 100644
index 0000000..8e2d8d0
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+
+#include "xfs_dinode.h"
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino)
+{
+ block_t blk;
+ xfs_dinode_t *core;
+ uint64_t offset;
+
+ xfs_debug("ino %lu", ino);
+
+ blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) <<
XFS_INFO(fs)->inode_shift;
+ if (offset > BLOCK_SIZE(fs)) {
+ xfs_error("Invalid inode offset in block!");
+ xfs_debug("offset: 0x%llx", offset);
+ goto out;
+ }
+
+ xfs_debug("blk %llu block offset 0x%llx", blk, blk <<
BLOCK_SHIFT(fs));
+ xfs_debug("inode offset in block (in bytes) is 0x%llx", offset);
+
+ core = (xfs_dinode_t *)((uint8_t *)get_cache(fs->fs_dev, blk) + offset);
+ if (be16_to_cpu(core->di_magic) !+ be16_to_cpu(*(uint16_t
*)XFS_DINODE_MAGIC)) {
+ xfs_error("Inode core's magic number does not match!");
+ xfs_debug("magic number 0x%04x", (be16_to_cpu(core->di_magic)));
+ goto out;
+ }
+
+ return core;
+
+out:
+ return NULL;
+}
diff --git a/core/fs/xfs/xfs_dinode.h b/core/fs/xfs/xfs_dinode.h
new file mode 100644
index 0000000..80deec7
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_DINODE_H_
+#define XFS_DINODE_H_
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino);
+
+#endif /* XFS_DINODE_H_ */
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
new file mode 100644
index 0000000..c52196a
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+
+#include "xfs_dir2.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end)
+{
+ char *s;
+ char *p;
+
+ s = malloc(end - start + 1);
+ if (!s)
+ malloc_error("string");
+
+ p = s;
+ while (start < end)
+ *p++ = *start++;
+
+ *p = '\0';
+
+ return s;
+}
+
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
+{
+ uint32_t hash;
+
+ /*
+ * Do four characters at a time as long as we can.
+ */
+ for (hash = 0; namelen >= 4; namelen -=4, name += 4)
+ hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2]
<< 7) ^
+ (name[3] << 0) ^ rol32(hash, 7 * 4);
+
+ /*
+ * Now do the rest of the characters.
+ */
+ switch (namelen) {
+ case 3:
+ return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] <<
0) ^
+ rol32(hash, 7 * 3);
+ case 2:
+ return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 *
2);
+ case 1:
+ return (name[0] << 0) ^ rol32(hash, 7 * 1);
+ default: /* case 0: */
+ return hash;
+ }
+}
+
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c)
+{
+ int count = c << XFS_INFO(fs)->dirblklog;
+ uint8_t *p;
+ uint8_t *buf;
+ off_t offset = 0;
+
+ buf = malloc(c * XFS_INFO(fs)->dirblksize);
+ if (!buf)
+ malloc_error("buffer memory");
+
+ memset(buf, 0, XFS_INFO(fs)->dirblksize);
+
+ while (count--) {
+ p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
+ memcpy(buf + offset, p, BLOCK_SIZE(fs));
+ offset += BLOCK_SIZE(fs);
+ }
+
+ return buf;
+}
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode
*parent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+ struct fs_info *fs = parent->fs;
+ struct inode *inode;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore = NULL;
+
+ xfs_debug("count %hhu i8count %hhu", sf->hdr.count,
sf->hdr.i8count);
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ (!sf->hdr.i8count ? 4 : 0));
+ while (count--) {
+ uint8_t *start_name = &sf_entry->name[0];
+ uint8_t *end_name = start_name + sf_entry->namelen;
+ char *name;
+
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ xfs_debug("entry name: %s", name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen +
+ (sf->hdr.i8count ? 8 : 4));
+ }
+
+ return NULL;
+
+found:
+ inode = xfs_new_inode(fs);
+
+ ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen));
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto out;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, ino);
+
+ inode->ino = ino;
+ inode->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ inode->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ inode->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ return inode;
+
+out:
+ free(inode);
+
+ return NULL;
+}
+
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode
*parent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t r;
+ block_t dir_blk;
+ struct fs_info *fs = parent->fs;
+ uint8_t *dirblk_buf;
+ uint8_t *p, *endp;
+ xfs_dir2_data_hdr_t *hdr;
+ struct inode *inode = NULL;
+ xfs_dir2_block_tail_t *btp;
+ xfs_dir2_data_unused_t *dup;
+ xfs_dir2_data_entry_t *dep;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+
+ bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+ dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+ hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+ if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ xfs_error("Block directory header's magic number does not
match!");
+ xfs_debug("hdr->magic: 0x%lx",
be32_to_cpu(hdr->magic));
+ goto out;
+ }
+
+ p = (uint8_t *)(hdr + 1);
+
+ btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+ endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp -
be32_to_cpu(btp->count));
+
+ while (p < endp) {
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+
+ dup = (xfs_dir2_data_unused_t *)p;
+ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+ p += be16_to_cpu(dup->length);
+ continue;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ p += xfs_dir2_data_entsize(dep->namelen);
+ }
+
+out:
+ free(dirblk_buf);
+
+ return NULL;
+
+found:
+ inode = xfs_new_inode(fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, ino);
+
+ inode->ino = ino;
+ XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >>
BLOCK_SHIFT(fs);
+ inode->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ inode->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ inode->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(dirblk_buf);
+ return inode;
+
+failed:
+ free(inode);
+ free(dirblk_buf);
+
+ return NULL;
+}
+
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_leaf_t *leaf;
+ xfs_bmbt_irec_t irec;
+ block_t leaf_blk, dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t hash = 0;
+ uint32_t hashwant;
+ uint32_t newdb, curdb = -1;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t
*)&core->di_literal_area[0]) +
+ be32_to_cpu(core->di_nextents) - 1);
+ leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+ BLOCK_SHIFT(parent->fs);
+
+ leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(parent->fs, leaf_blk,
+ irec.br_blockcount);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ xfs_error("Single leaf block header's magic number does not
match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+ /* Binary search */
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) -
1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ /* If hash is not the one we want, then the directory does not contain the
+ * entry we're looking for and there is nothing to do anymore.
+ */
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ for (lep = &leaf->ents[mid];
+ mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ newdb = xfs_dir2_dataptr_to_db(parent->fs,
be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ bmbt_irec_get(&irec,
+ ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
+ dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock)
>>
+ BLOCK_SHIFT(parent->fs);
+ buf = xfs_dir2_get_dirblks(parent->fs, dir_blk,
irec.br_blockcount);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not
match!");
+ goto out1;
+ }
+
+ curdb = newdb;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)((char *)buf +
+ xfs_dir2_dataptr_to_off(parent->fs,
be32_to_cpu(lep->address)));
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+out1:
+ free(buf);
+out:
+ free(leaf);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(parent->fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(parent->fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(parent->fs, ip, ino);
+
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+ BLOCK_SHIFT(parent->fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(buf);
+ free(leaf);
+
+ return ip;
+
+failed:
+ free(ip);
+ free(buf);
+ free(leaf);
+
+ return ip;
+}
+
+static xfs_fsblock_t
+select_child(xfs_dfiloff_t off,
+ xfs_bmbt_key_t *kp,
+ xfs_bmbt_ptr_t *pp,
+ int nrecs)
+{
+ int i;
+
+ for (i = 0; i < nrecs; i++) {
+ if (be64_to_cpu(kp[i].br_startoff) == off)
+ return be64_to_cpu(pp[i]);
+ if (be64_to_cpu(kp[i].br_startoff) > off) {
+ if (i == 0)
+ return be64_to_cpu(pp[i]);
+ else
+ return be64_to_cpu(pp[i-1]);
+ }
+ }
+
+ return be64_to_cpu(pp[nrecs - 1]);
+}
+
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ block_t fsblkno, int *error)
+{
+ uint32_t idx;
+ xfs_bmbt_irec_t irec;
+ block_t bno;
+ block_t nextbno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ int nextents;
+ xfs_bmbt_ptr_t *pp;
+ xfs_bmbt_key_t *kp;
+ xfs_btree_block_t *blk;
+ xfs_bmbt_rec_t *xp;
+
+ *error = 0;
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ xfs_debug("XFS_DINODE_FMT_EXTENTS");
+ for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) {
+ bmbt_irec_get(&irec,
+ ((xfs_bmbt_rec_t *)&core->di_literal_area[0])
+ idx);
+ if (fsblkno >= irec.br_startoff &&
+ fsblkno < irec.br_startoff + irec.br_blockcount)
+ break;
+ }
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ bno = NULLFSBLOCK;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ kp = XFS_BMDR_KEY_ADDR(rblock, 1);
+ bno = fsblock_to_bytes(fs,
+ select_child(fsblkno, kp, pp,
+ be16_to_cpu(rblock->bb_numrecs))) >>
BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ kp = XFS_BMBT_KEY_ADDR(fs, blk, 1);
+ bno = fsblock_to_bytes(fs,
+ select_child(fsblkno, kp, pp,
+ be16_to_cpu(blk->bb_numrecs))) >>
BLOCK_SHIFT(fs);
+ }
+
+ /* Find the records among leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ xp = (xfs_bmbt_rec_t *)XFS_BMBT_REC_ADDR(fs, blk, 1);
+ for (idx = 0; idx < nextents; idx++) {
+ bmbt_irec_get(&irec, xp + idx);
+ if (fsblkno >= irec.br_startoff &&
+ fsblkno < irec.br_startoff + irec.br_blockcount) {
+ nextbno = NULLFSBLOCK;
+ break;
+ }
+ }
+ if (nextbno == NULLFSBLOCK)
+ break;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
+ }
+
+ if (fsblkno < irec.br_startoff ||
+ fsblkno >= irec.br_startoff + irec.br_blockcount)
+ *error = 1;
+
+ return fsblock_to_bytes(fs,
+ fsblkno - irec.br_startoff + irec.br_startblock) >>
+ BLOCK_SHIFT(fs);
+}
+
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ block_t fsblkno;
+ xfs_da_intnode_t *node = NULL;
+ uint32_t hashwant;
+ uint32_t hash = 0;
+ xfs_da_node_entry_t *btree;
+ uint16_t max;
+ uint16_t span;
+ uint16_t probe;
+ int error;
+ xfs_dir2_data_hdr_t *data_hdr;
+ xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_entry_t *lep;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t newdb, curdb = -1;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core,
+ xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET),
+ &error);
+ if (error) {
+ xfs_error("Cannot find right rec!");
+ return NULL;
+ }
+
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Node's magic number does not match!");
+ goto out;
+ }
+
+ do {
+ if (!node->hdr.count)
+ goto out;
+
+ /* Given a hash to lookup, you read the node's btree array and
first
+ * "hashval" in the array that exceeds the given hash and it
can then
+ * be found in the block pointed by the "before" value.
+ */
+ max = be16_to_cpu(node->hdr.count);
+
+ probe = span = max/2;
+ for (btree = &node->btree[probe];
+ span > 4; btree = &node->btree[probe]) {
+ span /= 2;
+ hash = be32_to_cpu(btree->hashval);
+
+ if (hash < hashwant)
+ probe += span;
+ else if (hash > hashwant)
+ probe -= span;
+ else
+ break;
+ }
+
+ while ((probe > 0) && (be32_to_cpu(btree->hashval) >=
hashwant)) {
+ btree--;
+ probe--;
+ }
+
+ while ((probe < max) && (be32_to_cpu(btree->hashval) <
hashwant)) {
+ btree++;
+ probe++;
+ }
+
+ if (probe == max)
+ fsblkno = be32_to_cpu(node->btree[max-1].before);
+ else
+ fsblkno = be32_to_cpu(node->btree[probe].before);
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno,
&error);
+ if (error) {
+ xfs_error("Cannot find right rec!");
+ goto out;
+ }
+
+ free(node);
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs,
+ fsblkno, 1);
+ } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+
+ leaf = (xfs_dir2_leaf_t*)node;
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("Leaf's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) -
1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ /* If hash is not the one we want, then the directory does not contain the
+ * entry we're looking for and there is nothing to do anymore.
+ */
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ for (lep = &leaf->ents[mid];
+ mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ newdb = xfs_dir2_dataptr_to_db(parent->fs,
be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, newdb,
&error);
+ if (error) {
+ xfs_error("Cannot find data block!");
+ goto out;
+ }
+
+ buf = xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not
match!");
+ goto out1;
+ }
+
+ curdb = newdb;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)((char *)buf +
+ xfs_dir2_dataptr_to_off(parent->fs,
be32_to_cpu(lep->address)));
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+out1:
+ free(buf);
+
+out:
+ free(node);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(parent->fs);
+ ino = be64_to_cpu(dep->inumber);
+ ncore = xfs_dinode_get_core(parent->fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(parent->fs, ip, ino);
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+ BLOCK_SHIFT(parent->fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(buf);
+ free(node);
+
+ return ip;
+
+failed:
+ free(ip);
+ free(buf);
+ free(node);
+
+ return NULL;
+}
diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h
new file mode 100644
index 0000000..e1b9622
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_DIR2_H_
+#define XFS_DIR2_H_
+
+#include <core.h>
+#include <fs.h>
+
+#include "xfs.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end);
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c);
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen);
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ block_t fsblkno, int *error);
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode
*parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode
*parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+
+static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip)
+{
+ uint64_t last = 0;
+ xfs_bmbt_irec_t irec;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t
*)&dip->di_literal_area[0]) +
+ be32_to_cpu(dip->di_nextents) - 1);
+ last = irec.br_startoff + irec.br_blockcount;
+
+ return (last == XFS_INFO(fs)->dirleafblk + (1 <<
XFS_INFO(fs)->dirblklog));
+}
+
+#endif /* XFS_DIR2_H_ */
diff --git a/core/fs/xfs/xfs_fs.h b/core/fs/xfs/xfs_fs.h
new file mode 100644
index 0000000..587820e
--- /dev/null
+++ b/core/fs/xfs/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+ uint32_t d_mem; /* data buffer memory alignment */
+ uint32_t d_miniosz; /* min xfer size */
+ uint32_t d_maxiosz; /* max xfer size */
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ uint32_t fsx_xflags; /* xflags field value (get/set) */
+ uint32_t fsx_extsize; /* extsize field value (get/set)*/
+ uint32_t fsx_nextents; /* nextents field value (get) */
+ uint32_t fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
+#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
+#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
+#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
+#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
+#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
+#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back. The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output) */
+};
+
+/*
+ * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries
+ * are used exactly as in the getbmap structure. The getbmapx structure
+ * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ * is only used for the first structure. It contains input flags
+ * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled
+ * in by the XFS_IOC_GETBMAPX command for each returned structure after
+ * the first.
+ */
+struct getbmapx {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output). */
+ int32_t bmv_iflags; /* input flags (1st structure) */
+ int32_t bmv_oflags; /* output flags (after 1st structure)*/
+ int32_t bmv_unused1; /* future use */
+ int32_t bmv_unused2; /* future use */
+};
+
+/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */
+#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
+#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */
+#define BMV_IF_VALID \
+ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \
+ BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/* bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
+#define BMV_OF_LAST 0x4 /* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate. These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat! (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+ uint32_t fsd_dmevmask; /* corresponds to di_dmevmask */
+ __u16 fsd_padding;
+ __u16 fsd_dmstate; /* corresponds to di_dmstate */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+ __s16 l_type;
+ __s16 l_whence;
+ int64_t l_start;
+ int64_t l_len; /* len == 0 means until end of file */
+ int32_t l_sysid;
+ uint32_t l_pid;
+ int32_t l_pad[4]; /* reserve area */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+ uint32_t logsunit; /* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+ uint64_t freedata; /* free data section blocks */
+ uint64_t freertx; /* free rt extents */
+ uint64_t freeino; /* free inodes */
+ uint64_t allocino; /* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+ uint64_t resblks;
+ uint64_t resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION 0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */
+#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */
+#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */
+#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */
+#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */
+#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
+#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
+#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS 64
+#define XFS_MIN_LOG_BLOCKS 512ULL
+#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount *
(s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) * \
+ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG &
XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+ uint64_t newblocks; /* new data subvol size, fsblocks */
+ uint32_t imaxpct; /* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+ uint32_t newblocks; /* new log size, fsblocks */
+ uint32_t isint; /* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+ uint64_t newblocks; /* new realtime size, fsblocks */
+ uint32_t extsize; /* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT &
XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+ time_t tv_sec; /* seconds */
+ int32_t tv_nsec; /* and nanoseconds */
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+ uint64_t bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ uint32_t bs_uid; /* user id */
+ uint32_t bs_gid; /* group id */
+ uint32_t bs_rdev; /* device value */
+ int32_t bs_blksize; /* block size */
+ int64_t bs_size; /* file size */
+ xfs_bstime_t bs_atime; /* access time */
+ xfs_bstime_t bs_mtime; /* modify time */
+ xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ uint32_t bs_xflags; /* extended flags */
+ int32_t bs_extsize; /* extent size */
+ int32_t bs_extents; /* number of extents */
+ uint32_t bs_gen; /* generation count */
+ __u16 bs_projid_lo; /* lower part of project id */
+#define bs_projid bs_projid_lo /* (previously just bs_projid) */
+ __u16 bs_forkoff; /* inode fork offset in bytes */
+ __u16 bs_projid_hi; /* higher part of project id */
+ unsigned char bs_pad[10]; /* pad space, unused */
+ uint32_t bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+ uint64_t __user *lastip; /* last inode # pointer */
+ int32_t icount; /* count of entries in buffer */
+ void __user *ubuffer;/* user buffer for inode desc. */
+ int32_t __user *ocount; /* output count pointer */
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+ uint64_t xi_startino; /* starting inode number */
+ int32_t xi_alloccount; /* # bits set in allocmask */
+ uint64_t xi_allocmask; /* mask of allocated inodes */
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+ int32_t fd;
+ int32_t errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+ uint32_t fd; /* fd for FD_TO_HANDLE */
+ void __user *path; /* user pathname */
+ uint32_t oflags; /* open flags */
+ void __user *ihandle;/* user supplied handle */
+ uint32_t ihandlen; /* user supplied length */
+ void __user *ohandle;/* user buffer for handle */
+ uint32_t __user *ohandlen;/* user buffer length */
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ * XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle information */
+ struct fsdmidata __user *data; /* DMAPI data */
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+ uint32_t opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
+ uint32_t flags; /* which namespace to use */
+ uint32_t buflen; /* length of buffer supplied */
+ void __user *buffer; /* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+ uint32_t am_opcode;
+#define ATTR_OP_GET 1 /* return the indicated attr's value */
+#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
+ int32_t am_error;
+ void __user *am_attrname;
+ void __user *am_attrvalue;
+ uint32_t am_length;
+ uint32_t am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ uint32_t opcount;/* count of following multiop */
+ struct xfs_attr_multiop __user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+ __u16 fid_len; /* length of remainder */
+ __u16 fid_pad;
+ uint32_t fid_gen; /* generation number */
+ uint64_t fid_ino; /* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+ union {
+ int64_t align; /* force alignment of ha_fid */
+ xfs_fsid_t _ha_fsid; /* unique file system identifier */
+ } ha_u;
+ xfs_fid_t ha_fid; /* file system specific file ID */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \
+ - (char *) &(handle)) \
+ + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr)
+/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */
+/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */
+#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct
xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct
xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct
xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct
xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct
xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct
xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct
xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct
xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct
xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct
xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct
xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct
xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct
xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct
xfs_error_injection)
+/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */
+/* XFS_IOC_FREEZE -- FIFREEZE 119 */
+/* XFS_IOC_THAW -- FITHAW 120 */
+#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct
xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct
xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct
xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t)
+/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization. A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512. Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT 9
+#define BBSIZE (1<<BBSHIFT)
+#define BBMASK (BBSIZE-1)
+#define BTOBB(bytes) (((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes) ((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs) ((bbs) << BBSHIFT)
+#endif
+
+#endif /* XFS_FS_H_ */
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
new file mode 100644
index 0000000..0e013e5
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+
+#include "xfs_readdir.h"
+
+static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
+ uint32_t offset, xfs_ino_t ino, char *name,
+ size_t namelen)
+{
+ xfs_dinode_t *core;
+
+ dirent->d_ino = ino;
+ dirent->d_off = offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
+
+ core = xfs_dinode_get_core(fs, ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)",
ino);
+ return -1;
+ }
+
+ if (be16_to_cpu(core->di_mode) & S_IFDIR)
+ dirent->d_type = DT_DIR;
+ else if (be16_to_cpu(core->di_mode) & S_IFREG)
+ dirent->d_type = DT_REG;
+ else if (be16_to_cpu(core->di_mode) & S_IFLNK)
+ dirent->d_type = DT_LNK;
+
+ memcpy(dirent->d_name, name, namelen + 1);
+
+ return 0;
+}
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+ uint32_t offset = file->offset;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_ino_t ino;
+ struct fs_info *fs = file->fs;
+ int retval = 0;
+
+ xfs_debug("count %hhu i8count %hhu", sf->hdr.count,
sf->hdr.i8count);
+
+ if (file->offset + 1 > count)
+ return -1;
+
+ file->offset++;
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ (!sf->hdr.i8count ? 4 : 0));
+
+ if (file->offset - 1) {
+ offset = file->offset;
+ while (--offset) {
+ sf_entry = (xfs_dir2_sf_entry_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen +
+ (sf->hdr.i8count ? 8 : 4));
+ }
+ }
+
+ start_name = &sf_entry->name[0];
+ end_name = start_name + sf_entry->namelen;
+
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen));
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, (char *)name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+
+ return retval;
+}
+
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t r;
+ block_t dir_blk;
+ struct fs_info *fs = file->fs;
+ uint8_t *dirblk_buf;
+ uint8_t *p;
+ uint32_t offset;
+ xfs_dir2_data_hdr_t *hdr;
+ xfs_dir2_block_tail_t *btp;
+ xfs_dir2_data_unused_t *dup;
+ xfs_dir2_data_entry_t *dep;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_ino_t ino;
+ int retval = 0;
+
+ bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+ dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+ hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+ if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ xfs_error("Block directory header's magic number does not
match!");
+ xfs_debug("hdr->magic: 0x%lx",
be32_to_cpu(hdr->magic));
+
+ free(dirblk_buf);
+
+ return -1;
+ }
+
+ btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+
+ if (file->offset + 1 > be32_to_cpu(btp->count))
+ return -1;
+
+ file->offset++;
+
+ p = (uint8_t *)(hdr + 1);
+
+ if (file->offset - 1) {
+ offset = file->offset;
+ while (--offset) {
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ dup = (xfs_dir2_data_unused_t *)p;
+ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+ p += be16_to_cpu(dup->length);
+ continue;
+ }
+
+ p += xfs_dir2_data_entsize(dep->namelen);
+ }
+ }
+
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(dirblk_buf);
+ free(name);
+
+ return retval;
+}
+
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t irec;
+ struct fs_info *fs = file->fs;
+ xfs_dir2_leaf_t *leaf;
+ block_t leaf_blk, dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ uint32_t db;
+ unsigned int offset;
+ xfs_dir2_data_entry_t *dep;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ uint8_t *buf = NULL;
+ int retval = 0;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t
*)&core->di_literal_area[0]) +
+ be32_to_cpu(core->di_nextents) - 1);
+ leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
+ BLOCK_SHIFT(file->fs);
+
+ leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(fs, leaf_blk,
+ irec.br_blockcount);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ xfs_error("Single leaf block header's magic number does not
match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
+ goto out;
+
+ lep = &leaf->ents[file->offset++];
+
+ /* Skip over stale leaf entries */
+ for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+ lep++, file->offset++);
+
+ db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]
+ db);
+
+ dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
BLOCK_SHIFT(fs);
+
+ buf = xfs_dir2_get_dirblks(fs, dir_blk, irec.br_blockcount);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic number does not match!");
+ goto out1;
+ }
+
+ offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+ dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+ free(buf);
+ free(leaf);
+
+ return retval;
+
+out1:
+ free(buf);
+
+out:
+ free(leaf);
+
+ return -1;
+}
+
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ struct fs_info *fs = file->fs;
+ xfs_bmbt_irec_t irec;
+ uint32_t node_off = 0;
+ block_t fsblkno;
+ xfs_da_intnode_t *node = NULL;
+ struct inode *inode = file->inode;
+ int error;
+ xfs_dir2_data_hdr_t *data_hdr;
+ xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_entry_t *lep;
+ unsigned int offset;
+ xfs_dir2_data_entry_t *dep;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ uint32_t db;
+ uint8_t *buf = NULL;
+ int retval = 0;
+
+ do {
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t
*)&core->di_literal_area[0] +
+ ++node_off);
+ } while (irec.br_startoff < xfs_dir2_byte_to_db(fs,
XFS_DIR2_LEAF_OFFSET));
+
+ fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >>
BLOCK_SHIFT(fs);
+
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Node's magic number does not match!");
+ goto out;
+ }
+
+try_next_btree:
+ if (!node->hdr.count ||
+ XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
+ goto out;
+
+ fsblkno =
be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
+ fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
+ if (error) {
+ xfs_error("Cannot find leaf rec!");
+ goto out;
+ }
+
+ leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("Leaf's magic number does not match!");
+ goto out1;
+ }
+
+ if (!leaf->hdr.count ||
+ XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
+ XFS_PVT(inode)->i_btree_offset++;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ free(leaf);
+ goto try_next_btree;
+ }
+
+ lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
+
+ /* Skip over stale leaf entries */
+ for ( ; XFS_PVT(inode)->i_leaf_ent_offset <
be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+ lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
+
+ if (XFS_PVT(inode)->i_leaf_ent_offset ==
be16_to_cpu(leaf->hdr.count)) {
+ XFS_PVT(inode)->i_btree_offset++;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ free(leaf);
+ goto try_next_btree;
+ } else {
+ XFS_PVT(inode)->i_leaf_ent_offset++;
+ }
+
+ db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+ fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
+ if (error) {
+ xfs_error("Cannot find data block!");
+ goto out1;
+ }
+
+ buf = xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out2;
+ }
+
+ offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+ dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber), name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+ free(buf);
+ free(leaf);
+ free(node);
+
+ return retval;
+
+out2:
+ free(buf);
+
+out1:
+ free(leaf);
+
+out:
+ free(node);
+
+ XFS_PVT(inode)->i_btree_offset = 0;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+
+ return -1;
+}
diff --git a/core/fs/xfs/xfs_readdir.h b/core/fs/xfs/xfs_readdir.h
new file mode 100644
index 0000000..2e564ec
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_READDIR_H_
+#define XFS_READDIR_H_
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+
+#endif /* XFS_READDIR_H_ */
diff --git a/core/fs/xfs/xfs_sb.h b/core/fs/xfs/xfs_sb.h
new file mode 100644
index 0000000..12024ab
--- /dev/null
+++ b/core/fs/xfs/xfs_sb.h
@@ -0,0 +1,206 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_SB_H_
+#define XFS_SB_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef unsigned char uuid_t[16];
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC "XFSB" /* 'XFSB' */
+#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
+#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
+#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ALLFBITS 0xfff0
+#define XFS_SB_VERSION_SASHFBITS 0xf000
+#define XFS_SB_VERSION_REALFBITS 0x0ff0
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
+#define XFS_SB_VERSION_SECTORBIT 0x0800
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
+#define XFS_SB_VERSION_MOREBITSBIT 0x8000
+#define XFS_SB_VERSION_OKSASHFBITS \
+ (XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT | \
+ XFS_SB_VERSION_BORGBIT)
+#define XFS_SB_VERSION_OKREALFBITS \
+ (XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_SHAREDBIT | \
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+#define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2. Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */
+
+#define XFS_SB_VERSION2_OKREALFBITS \
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT | \
+ XFS_SB_VERSION2_PROJID32BIT)
+#define XFS_SB_VERSION2_OKSASHFBITS \
+ (0)
+#define XFS_SB_VERSION2_OKREALBITS \
+ (XFS_SB_VERSION2_OKREALFBITS | \
+ XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+ XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+ XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+ XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+ XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+ XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+ XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+ XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+ XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+ XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+ XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+ XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+ XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+ XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+ XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
+#define XFS_SB_UUID XFS_SB_MVAL(UUID)
+#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
+#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
+#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
+#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
+#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
+#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
+#define XFS_SB_MOD_BITS \
+ (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+ XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+ XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
+#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN 0
+
+#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum &
XFS_SB_VERSION_NUMBITS)
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr))
+
+#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \
+ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \
+ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSB(mp,bb) \
+ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) <<
(mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b) \
+ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >>
(mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
+
+#endif /* XFS_SB_H_ */
diff --git a/core/fs/xfs/xfs_types.h b/core/fs/xfs/xfs_types.h
new file mode 100644
index 0000000..9280886
--- /dev/null
+++ b/core/fs/xfs/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_TYPES_H_
+#define XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE } boolean_t;
+typedef uint32_t prid_t; /* project ID */
+typedef uint32_t inst_t; /* an instruction */
+
+typedef int64_t xfs_off_t; /* <file offset> type */
+typedef unsigned long long xfs_ino_t; /* <inode> type */
+typedef int64_t xfs_daddr_t; /* <disk address> type */
+typedef char * xfs_caddr_t; /* <core address> type */
+typedef uint32_t xfs_dev_t;
+typedef uint32_t xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_agnumber_t; /* allocation group number */
+typedef int32_t xfs_extnum_t; /* # of extents in a file */
+typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef int64_t xfs_fsize_t; /* bytes in a file */
+typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
+
+typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
+typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
+
+typedef int64_t xfs_lsn_t; /* log sequence number */
+typedef int32_t xfs_tid_t; /* transaction identifier */
+
+typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef uint64_t xfs_dfiloff_t; /* block number in a file */
+typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+
+typedef uint64_t xfs_fileoff_t; /* block number in a file */
+typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define NULLDFSBNO ((xfs_dfsbno_t)-1)
+#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
+#define NULLDRTBNO ((xfs_drtbno_t)-1)
+#define NULLDFILOFF ((xfs_dfiloff_t)-1)
+
+#define NULLFSBLOCK ((xfs_fsblock_t)-1)
+#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
+#define NULLRTBLOCK ((xfs_rtblock_t)-1)
+#define NULLFILEOFF ((xfs_fileoff_t)-1)
+
+#define NULLAGBLOCK ((xfs_agblock_t)-1)
+#define NULLAGNUMBER ((xfs_agnumber_t)-1)
+#define NULLEXTNUM ((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
+#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
+#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS 3
+#define MINABTPTRS 2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN 256
+
+typedef enum {
+ XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+ XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+ XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+ const unsigned char *name;
+ int len;
+};
+
+#endif /* XFS_TYPES_H_ */
diff --git a/core/include/fs.h b/core/include/fs.h
index e1f5733..a9c76ae 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -98,9 +98,9 @@ struct inode {
const char *name; /* Name, valid for generic path search only */
int refcnt;
int mode; /* FILE , DIR or SYMLINK */
- uint32_t size;
- uint32_t blocks; /* How many blocks the file take */
- uint32_t ino; /* Inode number */
+ uint64_t size;
+ uint64_t blocks; /* How many blocks the file take */
+ uint64_t ino; /* Inode number */
uint32_t atime; /* Access time */
uint32_t mtime; /* Modify time */
uint32_t ctime; /* Create time */
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index a2f859d..a1f96b7 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -39,6 +39,8 @@ ROOT_FS_OPS:
dd ext2_fs_ops
extern ntfs_fs_ops
dd ntfs_fs_ops
+ extern xfs_fs_ops
+ dd xfs_fs_ops
extern btrfs_fs_ops
dd btrfs_fs_ops
dd 0
diff --git a/extlinux/main.c b/extlinux/main.c
index 73f3fbe..d1a800c 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -14,7 +14,8 @@
/*
* extlinux.c
*
- * Install the syslinux boot block on an fat, ntfs, ext2/3/4 and btrfs
filesystem
+ * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs and xfs
+ * filesystem.
*/
#define _GNU_SOURCE /* Enable everything */
@@ -46,6 +47,10 @@
#include "btrfs.h"
#include "fat.h"
#include "ntfs.h"
+#include "xfs.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "misc.h"
#include "../version.h"
#include "syslxint.h"
#include "syslxcom.h" /* common functions shared with extlinux and
syslinux */
@@ -64,6 +69,13 @@
#define EXT2_SUPER_OFFSET 1024
#endif
+/* Since we have unused 2048 bytes in the primary AG of an XFS partition,
+ * we will use the first 0~512 bytes starting from 2048 for the Syslinux
+ * boot sector.
+ */
+#define XFS_BOOTSECT_OFFSET (4 << SECTOR_SHIFT)
+#define XFS_SUPPORTED_BLOCKSIZE 4096 /* 4 KiB filesystem block size */
+
/* the btrfs partition first 64K blank area is used to store boot sector and
boot image, the boot sector is from 0~512, the boot image starts after */
#define BTRFS_BOOTSECT_AREA 65536
@@ -295,7 +307,8 @@ int patch_file_and_bootblock(int fd, const char *dir, int
devfd)
nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
nsect += 2; /* Two sectors for the ADV */
sectp = alloca(sizeof(sector_t) * nsect);
- if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) {
+ if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS ||
+ fs_type == XFS) {
if (sectmap(fd, sectp, nsect)) {
perror("bmap");
exit(1);
@@ -328,6 +341,7 @@ int install_bootblock(int fd, const char *device)
struct btrfs_super_block sb2;
struct fat_boot_sector sb3;
struct ntfs_boot_sector sb4;
+ xfs_sb_t sb5;
bool ok = false;
if (fs_type == EXT2) {
@@ -335,6 +349,7 @@ int install_bootblock(int fd, const char *device)
perror("reading superblock");
return 1;
}
+
if (sb.s_magic == EXT2_SUPER_MAGIC)
ok = true;
} else if (fs_type == BTRFS) {
@@ -350,6 +365,7 @@ int install_bootblock(int fd, const char *device)
perror("reading fat superblock");
return 1;
}
+
if (fat_check_sb_fields(&sb3))
ok = true;
} else if (fs_type == NTFS) {
@@ -360,12 +376,34 @@ int install_bootblock(int fd, const char *device)
if (ntfs_check_sb_fields(&sb4))
ok = true;
+ } else if (fs_type == XFS) {
+ if (xpread(fd, &sb5, sizeof sb5, 0) != sizeof sb5) {
+ perror("reading xfs superblock");
+ return 1;
+ }
+
+ if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) {
+ if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) {
+ fprintf(stderr,
+ "You need to have 4 KiB filesystem block size for "
+ " being able to install Syslinux in your XFS "
+ "partition (because there is no enough space in MBR to "
+ "determine where Syslinux bootsector can be installed "
+ "regardless the filesystem block size)\n");
+ return 1;
+ }
+
+ ok = true;
+ }
}
+
if (!ok) {
- fprintf(stderr, "no fat, ntfs, ext2/3/4 or btrfs superblock found on
%s\n",
- device);
+ fprintf(stderr,
+ "no fat, ntfs, ext2/3/4, btrfs or xfs superblock found on %s\n",
+ device);
return 1;
}
+
if (fs_type == VFAT) {
struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) !=
FAT_bsHeadLen ||
@@ -385,6 +423,12 @@ int install_bootblock(int fd, const char *device)
perror("writing ntfs bootblock");
return 1;
}
+ } else if (fs_type == XFS) {
+ if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len,
+ XFS_BOOTSECT_OFFSET) != syslinux_bootsect_len) {
+ perror("writing xfs bootblock");
+ return 1;
+ }
} else {
if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
!= syslinux_bootsect_len) {
@@ -396,11 +440,61 @@ int install_bootblock(int fd, const char *device)
return 0;
}
+static int rewrite_boot_image(int devfd, const char *filename)
+{
+ int fd;
+ int ret;
+ int modbytes;
+ char path[PATH_MAX];
+ char slash;
+
+ /* Let's create LDLINUX.SYS file again (if it already exists, of
course) */
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
+ S_IRUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ perror(filename);
+ return -1;
+ }
+
+ /* Write boot image data into LDLINUX.SYS file */
+ ret = xpwrite(fd, boot_image, boot_image_len, 0);
+ if (ret != boot_image_len) {
+ perror("writing bootblock");
+ goto error;
+ }
+
+ /* Write ADV */
+ ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len);
+ if (ret != 2 * ADV_SIZE) {
+ fprintf(stderr, "%s: write failure on %s\n", program, filename);
+ goto error;
+ }
+
+ sscanf(filename, "%s%cldlinux.sys", path, &slash);
+
+ /* Map the file, and patch the initial sector accordingly */
+ modbytes = patch_file_and_bootblock(fd, path, devfd);
+
+ /* Write the patch area again - this relies on the file being overwritten
+ * in place! */
+ ret = xpwrite(fd, boot_image, modbytes, 0);
+ if (ret != modbytes) {
+ fprintf(stderr, "%s: write failure on %s\n", program, filename);
+ goto error;
+ }
+
+ return fd;
+
+error:
+ close(fd);
+
+ return -1;
+}
+
int ext2_fat_install_file(const char *path, int devfd, struct stat *rst)
{
char *file, *oldfile;
int fd = -1, dirfd = -1;
- int modbytes;
int r1, r2;
r1 = asprintf(&file, "%s%sldlinux.sys",
@@ -429,30 +523,9 @@ int ext2_fat_install_file(const char *path, int devfd,
struct stat *rst)
}
close(fd);
- fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
- S_IRUSR | S_IRGRP | S_IROTH);
- if (fd < 0) {
- perror(file);
+ fd = rewrite_boot_image(devfd, file);
+ if (fd < 0)
goto bail;
- }
-
- /* Write it the first time */
- if (xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ||
- xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
- boot_image_len) != 2 * ADV_SIZE) {
- fprintf(stderr, "%s: write failure on %s\n", program, file);
- goto bail;
- }
-
- /* Map the file, and patch the initial sector accordingly */
- modbytes = patch_file_and_bootblock(fd, path, devfd);
-
- /* Write the patch area again - this relies on the file being
- overwritten in place! */
- if (xpwrite(fd, boot_image, modbytes, 0) != modbytes) {
- fprintf(stderr, "%s: write failure on %s\n", program, file);
- goto bail;
- }
/* Attempt to set immutable flag and remove all write access */
/* Only set immutable flag if file is owned by root */
@@ -515,6 +588,70 @@ int btrfs_install_file(const char *path, int devfd, struct
stat *rst)
}
/*
+ * Due to historical reasons (SGI IRIX's design of disk layouts), the first
+ * sector in the primary AG on XFS filesystems contains the superblock, which
is
+ * a problem with bootloaders that rely on BIOSes (that load VBRs which are
+ * (located in the first sector of the partition).
+ *
+ * Thus, we need to handle this issue, otherwise Syslinux will damage the
XFS's
+ * superblock.
+ */
+static int xfs_install_file(const char *path, int devfd, struct stat *rst)
+{
+ static char file[PATH_MAX];
+ int dirfd = -1;
+ int fd = -1;
+
+ snprintf(file, PATH_MAX, "%s%sldlinux.sys",
+ path, path[0] && path[strlen(path) - 1] == '/' ?
"" : "/");
+
+ dirfd = open(path, O_RDONLY | O_DIRECTORY);
+ if (dirfd < 0) {
+ perror(path);
+ goto bail;
+ }
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ perror(file);
+ goto bail;
+ }
+ } else {
+ clear_attributes(fd);
+ }
+
+ close(fd);
+
+ fd = rewrite_boot_image(devfd, file);
+ if (fd < 0)
+ goto bail;
+
+ /* Attempt to set immutable flag and remove all write access */
+ /* Only set immutable flag if file is owned by root */
+ set_attributes(fd);
+
+ if (fstat(fd, rst)) {
+ perror(file);
+ goto bail;
+ }
+
+ close(dirfd);
+ close(fd);
+
+ return 0;
+
+bail:
+ if (dirfd >= 0)
+ close(dirfd);
+
+ if (fd >= 0)
+ close(fd);
+
+ return 1;
+}
+
+/*
* * test if path is a subvolume:
* * this function return
* * 0-> path exists but it is not a subvolume
@@ -748,11 +885,14 @@ static char * get_default_subvol(char * rootdir, char *
subvol)
int install_file(const char *path, int devfd, struct stat *rst)
{
- if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
- return ext2_fat_install_file(path, devfd, rst);
- else if (fs_type == BTRFS)
- return btrfs_install_file(path, devfd, rst);
- return 1;
+ if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
+ return ext2_fat_install_file(path, devfd, rst);
+ else if (fs_type == BTRFS)
+ return btrfs_install_file(path, devfd, rst);
+ else if (fs_type == XFS)
+ return xfs_install_file(path, devfd, rst);
+
+ return 1;
}
#ifdef __KLIBC__
@@ -847,14 +987,22 @@ static const char *find_device(const char *mtab_file,
dev_t dev)
}
break;
+ case XFS:
+ if (!strcmp(mnt->mnt_type, "xfs") &&
!stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
case NONE:
break;
}
+
if (done) {
devname = strdup(mnt->mnt_fsname);
break;
}
}
+
endmntent(mtab);
return devname;
@@ -1098,6 +1246,7 @@ static int open_device(const char *path, struct stat *st,
const char **_devname)
fprintf(stderr, "%s: statfs %s: %s\n", program, path,
strerror(errno));
return -1;
}
+
if (sfs.f_type == EXT2_SUPER_MAGIC)
fs_type = EXT2;
else if (sfs.f_type == BTRFS_SUPER_MAGIC)
@@ -1106,10 +1255,13 @@ static int open_device(const char *path, struct stat
*st, const char **_devname)
fs_type = VFAT;
else if (sfs.f_type == NTFS_SB_MAGIC ||
sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
- fs_type = NTFS;
+ fs_type = NTFS;
+ else if (sfs.f_type == XFS_SUPER_MAGIC)
+ fs_type = XFS;
if (!fs_type) {
- fprintf(stderr, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem:
%s\n",
+ fprintf(stderr,
+ "%s: not a fat, ntfs, ext2/3/4, btrfs or xfs filesystem: %s\n",
program, path);
return -1;
}
@@ -1143,6 +1295,16 @@ static int btrfs_read_adv(int devfd)
return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
}
+static inline int xfs_read_adv(int devfd)
+{
+ const size_t adv_size = 2 * ADV_SIZE;
+
+ if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size)
+ return -1;
+
+ return syslinux_validate_adv(syslinux_adv) ? 1 : 0;
+}
+
static int ext_read_adv(const char *path, int devfd, const char **namep)
{
int err;
@@ -1151,6 +1313,9 @@ static int ext_read_adv(const char *path, int devfd, const
char **namep)
if (fs_type == BTRFS) {
/* btrfs "ldlinux.sys" is in 64k blank area */
return btrfs_read_adv(devfd);
+ } else if (fs_type == XFS) {
+ /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */
+ return xfs_read_adv(devfd);
} else {
err = read_adv(path, name = "ldlinux.sys");
if (err == 2) /* ldlinux.sys does not exist */
diff --git a/extlinux/misc.h b/extlinux/misc.h
new file mode 100644
index 0000000..7f2f1b3
--- /dev/null
+++ b/extlinux/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+ return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL)
<< 56) |
+ (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+ (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) << 8) |
+ (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+ return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) <<
24) |
+ (((uint32_t)val & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)val & (uint32_t)0x00ff0000UL) >> 8) |
+ (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+ return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+ (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/extlinux/xfs.h b/extlinux/xfs.h
new file mode 100644
index 0000000..412c266
--- /dev/null
+++ b/extlinux/xfs.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#define XFS_SUPER_MAGIC 0x58465342
+
+#endif /* XFS_H_ */
diff --git a/extlinux/xfs_fs.h b/extlinux/xfs_fs.h
new file mode 100644
index 0000000..587820e
--- /dev/null
+++ b/extlinux/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+ uint32_t d_mem; /* data buffer memory alignment */
+ uint32_t d_miniosz; /* min xfer size */
+ uint32_t d_maxiosz; /* max xfer size */
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ uint32_t fsx_xflags; /* xflags field value (get/set) */
+ uint32_t fsx_extsize; /* extsize field value (get/set)*/
+ uint32_t fsx_nextents; /* nextents field value (get) */
+ uint32_t fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
+#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
+#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
+#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
+#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
+#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
+#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back. The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output) */
+};
+
+/*
+ * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries
+ * are used exactly as in the getbmap structure. The getbmapx structure
+ * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ * is only used for the first structure. It contains input flags
+ * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled
+ * in by the XFS_IOC_GETBMAPX command for each returned structure after
+ * the first.
+ */
+struct getbmapx {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output). */
+ int32_t bmv_iflags; /* input flags (1st structure) */
+ int32_t bmv_oflags; /* output flags (after 1st structure)*/
+ int32_t bmv_unused1; /* future use */
+ int32_t bmv_unused2; /* future use */
+};
+
+/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */
+#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
+#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */
+#define BMV_IF_VALID \
+ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \
+ BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/* bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
+#define BMV_OF_LAST 0x4 /* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate. These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat! (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+ uint32_t fsd_dmevmask; /* corresponds to di_dmevmask */
+ __u16 fsd_padding;
+ __u16 fsd_dmstate; /* corresponds to di_dmstate */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+ __s16 l_type;
+ __s16 l_whence;
+ int64_t l_start;
+ int64_t l_len; /* len == 0 means until end of file */
+ int32_t l_sysid;
+ uint32_t l_pid;
+ int32_t l_pad[4]; /* reserve area */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+ uint32_t logsunit; /* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+ uint64_t freedata; /* free data section blocks */
+ uint64_t freertx; /* free rt extents */
+ uint64_t freeino; /* free inodes */
+ uint64_t allocino; /* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+ uint64_t resblks;
+ uint64_t resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION 0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */
+#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */
+#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */
+#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */
+#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */
+#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
+#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
+#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS 64
+#define XFS_MIN_LOG_BLOCKS 512ULL
+#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount *
(s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) * \
+ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG &
XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+ uint64_t newblocks; /* new data subvol size, fsblocks */
+ uint32_t imaxpct; /* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+ uint32_t newblocks; /* new log size, fsblocks */
+ uint32_t isint; /* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+ uint64_t newblocks; /* new realtime size, fsblocks */
+ uint32_t extsize; /* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT &
XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+ time_t tv_sec; /* seconds */
+ int32_t tv_nsec; /* and nanoseconds */
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+ uint64_t bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ uint32_t bs_uid; /* user id */
+ uint32_t bs_gid; /* group id */
+ uint32_t bs_rdev; /* device value */
+ int32_t bs_blksize; /* block size */
+ int64_t bs_size; /* file size */
+ xfs_bstime_t bs_atime; /* access time */
+ xfs_bstime_t bs_mtime; /* modify time */
+ xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ uint32_t bs_xflags; /* extended flags */
+ int32_t bs_extsize; /* extent size */
+ int32_t bs_extents; /* number of extents */
+ uint32_t bs_gen; /* generation count */
+ __u16 bs_projid_lo; /* lower part of project id */
+#define bs_projid bs_projid_lo /* (previously just bs_projid) */
+ __u16 bs_forkoff; /* inode fork offset in bytes */
+ __u16 bs_projid_hi; /* higher part of project id */
+ unsigned char bs_pad[10]; /* pad space, unused */
+ uint32_t bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+ uint64_t __user *lastip; /* last inode # pointer */
+ int32_t icount; /* count of entries in buffer */
+ void __user *ubuffer;/* user buffer for inode desc. */
+ int32_t __user *ocount; /* output count pointer */
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+ uint64_t xi_startino; /* starting inode number */
+ int32_t xi_alloccount; /* # bits set in allocmask */
+ uint64_t xi_allocmask; /* mask of allocated inodes */
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+ int32_t fd;
+ int32_t errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+ uint32_t fd; /* fd for FD_TO_HANDLE */
+ void __user *path; /* user pathname */
+ uint32_t oflags; /* open flags */
+ void __user *ihandle;/* user supplied handle */
+ uint32_t ihandlen; /* user supplied length */
+ void __user *ohandle;/* user buffer for handle */
+ uint32_t __user *ohandlen;/* user buffer length */
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ * XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle information */
+ struct fsdmidata __user *data; /* DMAPI data */
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+ uint32_t opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
+ uint32_t flags; /* which namespace to use */
+ uint32_t buflen; /* length of buffer supplied */
+ void __user *buffer; /* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+ uint32_t am_opcode;
+#define ATTR_OP_GET 1 /* return the indicated attr's value */
+#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
+ int32_t am_error;
+ void __user *am_attrname;
+ void __user *am_attrvalue;
+ uint32_t am_length;
+ uint32_t am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ uint32_t opcount;/* count of following multiop */
+ struct xfs_attr_multiop __user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+ __u16 fid_len; /* length of remainder */
+ __u16 fid_pad;
+ uint32_t fid_gen; /* generation number */
+ uint64_t fid_ino; /* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+ union {
+ int64_t align; /* force alignment of ha_fid */
+ xfs_fsid_t _ha_fsid; /* unique file system identifier */
+ } ha_u;
+ xfs_fid_t ha_fid; /* file system specific file ID */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \
+ - (char *) &(handle)) \
+ + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr)
+/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */
+/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */
+#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct
xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct
xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct
xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct
xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct
xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct
xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct
xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct
xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct
xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct
xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct
xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct
xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct
xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct
xfs_error_injection)
+/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */
+/* XFS_IOC_FREEZE -- FIFREEZE 119 */
+/* XFS_IOC_THAW -- FITHAW 120 */
+#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct
xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct
xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct
xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t)
+/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization. A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512. Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT 9
+#define BBSIZE (1<<BBSHIFT)
+#define BBMASK (BBSIZE-1)
+#define BTOBB(bytes) (((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes) ((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs) ((bbs) << BBSHIFT)
+#endif
+
+#endif /* XFS_FS_H_ */
diff --git a/extlinux/xfs_sb.h b/extlinux/xfs_sb.h
new file mode 100644
index 0000000..8f72d6a
--- /dev/null
+++ b/extlinux/xfs_sb.h
@@ -0,0 +1,476 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_SB_H_
+#define XFS_SB_H__
+
+#include <stddef.h>
+
+#include <sys/types.h>
+#include <uuid/uuid.h>
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC "XFSB" /* 'XFSB' */
+#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
+#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
+#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ALLFBITS 0xfff0
+#define XFS_SB_VERSION_SASHFBITS 0xf000
+#define XFS_SB_VERSION_REALFBITS 0x0ff0
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
+#define XFS_SB_VERSION_SECTORBIT 0x0800
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
+#define XFS_SB_VERSION_MOREBITSBIT 0x8000
+#define XFS_SB_VERSION_OKSASHFBITS \
+ (XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT | \
+ XFS_SB_VERSION_BORGBIT)
+#define XFS_SB_VERSION_OKREALFBITS \
+ (XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_SHAREDBIT | \
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+#define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2. Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */
+
+#define XFS_SB_VERSION2_OKREALFBITS \
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT | \
+ XFS_SB_VERSION2_PROJID32BIT)
+#define XFS_SB_VERSION2_OKSASHFBITS \
+ (0)
+#define XFS_SB_VERSION2_OKREALBITS \
+ (XFS_SB_VERSION2_OKREALFBITS | \
+ XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Superblock - in core version. Must match the ondisk version below.
+ * Must be padded to 64 bit alignment.
+ */
+typedef struct xfs_sb {
+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ uint16_t sb_sectsize; /* volume sector size, bytes */
+ uint16_t sb_inodesize; /* inode size, bytes */
+ uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ uint8_t sb_rextslog; /* log2 of sb_rextents */
+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ uint64_t sb_icount; /* allocated inodes */
+ uint64_t sb_ifree; /* free inodes */
+ uint64_t sb_fdblocks; /* free data blocks */
+ uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ uint16_t sb_qflags; /* quota flags */
+ uint8_t sb_flags; /* misc. flags */
+ uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ uint32_t sb_unit; /* stripe or raid unit */
+ uint32_t sb_width; /* stripe or raid width */
+ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ uint8_t sb_logsectlog; /* log2 of the log sector size */
+ uint16_t sb_logsectsize; /* sector size for the log, bytes */
+ uint32_t sb_logsunit; /* stripe unit size for the log */
+ uint32_t sb_features2; /* additional feature bits */
+
+ /*
+ * bad features2 field as a result of failing to pad the sb
+ * structure to 64 bits. Some machines will be using this field
+ * for features2 bits. Easiest just to mark it bad and not use
+ * it for anything else.
+ */
+ uint32_t sb_bad_features2;
+
+ /* must be padded to 64 bit alignment */
+} xfs_sb_t;
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+ XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+ XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+ XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+ XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+ XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+ XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+ XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+ XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+ XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+ XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+ XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+ XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+ XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+ XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
+#define XFS_SB_UUID XFS_SB_MVAL(UUID)
+#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
+#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
+#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
+#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
+#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
+#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
+#define XFS_SB_MOD_BITS \
+ (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+ XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+ XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
+#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN 0
+
+#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum &
XFS_SB_VERSION_NUMBITS)
+
+static inline int xfs_sb_good_version(xfs_sb_t *sbp)
+{
+ /* We always support version 1-3 */
+ if (sbp->sb_versionnum >= XFS_SB_VERSION_1 &&
+ sbp->sb_versionnum <= XFS_SB_VERSION_3)
+ return 1;
+
+ /* We support version 4 if all feature bits are supported */
+ if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) {
+ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) ||
+ ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
+ (sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)))
+ return 0;
+
+ if ((sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) &&
+ sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
+ return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Detect a mismatched features2 field. Older kernels read/wrote
+ * this into the wrong slot, so to be safe we keep them in sync.
+ */
+static inline int xfs_sb_has_mismatched_features2(xfs_sb_t *sbp)
+{
+ return (sbp->sb_bad_features2 != sbp->sb_features2);
+}
+
+static inline unsigned xfs_sb_version_tonew(unsigned v)
+{
+ if (v == XFS_SB_VERSION_1)
+ return XFS_SB_VERSION_4;
+
+ if (v == XFS_SB_VERSION_2)
+ return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
+
+ return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT |
+ XFS_SB_VERSION_NLINKBIT;
+}
+
+static inline unsigned xfs_sb_version_toold(unsigned v)
+{
+ if (v & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT))
+ return 0;
+ if (v & XFS_SB_VERSION_NLINKBIT)
+ return XFS_SB_VERSION_3;
+ if (v & XFS_SB_VERSION_ATTRBIT)
+ return XFS_SB_VERSION_2;
+ return XFS_SB_VERSION_1;
+}
+
+static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp)
+{
+ return sbp->sb_versionnum == XFS_SB_VERSION_2 ||
+ sbp->sb_versionnum == XFS_SB_VERSION_3 ||
+ (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
+}
+
+static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
+{
+ if (sbp->sb_versionnum == XFS_SB_VERSION_1)
+ sbp->sb_versionnum = XFS_SB_VERSION_2;
+ else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+ sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
+ else
+ sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
+}
+
+static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp)
+{
+ return sbp->sb_versionnum == XFS_SB_VERSION_3 ||
+ (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
+}
+
+static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp)
+{
+ if (sbp->sb_versionnum <= XFS_SB_VERSION_2)
+ sbp->sb_versionnum = XFS_SB_VERSION_3;
+ else
+ sbp->sb_versionnum |= XFS_SB_VERSION_NLINKBIT;
+}
+
+static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
+}
+
+static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
+{
+ if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+ sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
+ else
+ sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) |
+ XFS_SB_VERSION_QUOTABIT;
+}
+
+static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT);
+}
+
+static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
+}
+
+static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT);
+}
+
+static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
+}
+
+static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
+}
+
+static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
+}
+
+static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
+}
+
+static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
+}
+
+static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+ (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
+}
+
+/*
+ * sb_features2 bit version macros.
+ *
+ * For example, for a bit defined as XFS_SB_VERSION2_FUNBIT, has a macro:
+ *
+ * SB_VERSION_HASFUNBIT(xfs_sb_t *sbp)
+ * ((xfs_sb_version_hasmorebits(sbp) &&
+ * ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT)
+ */
+
+static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
+{
+ return xfs_sb_version_hasmorebits(sbp) &&
+ (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT);
+}
+
+static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
+{
+ return xfs_sb_version_hasmorebits(sbp) &&
+ (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT);
+}
+
+static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
+{
+ sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
+ sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
+}
+
+static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
+{
+ sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT;
+ if (!sbp->sb_features2)
+ sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT;
+}
+
+static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
+{
+ return xfs_sb_version_hasmorebits(sbp) &&
+ (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT);
+}
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */
+#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr))
+
+#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \
+ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \
+ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSB(mp,bb) \
+ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) <<
(mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b) \
+ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >>
(mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
+
+#endif /* XFS_SB_H_ */
diff --git a/extlinux/xfs_types.h b/extlinux/xfs_types.h
new file mode 100644
index 0000000..9280886
--- /dev/null
+++ b/extlinux/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_TYPES_H_
+#define XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE } boolean_t;
+typedef uint32_t prid_t; /* project ID */
+typedef uint32_t inst_t; /* an instruction */
+
+typedef int64_t xfs_off_t; /* <file offset> type */
+typedef unsigned long long xfs_ino_t; /* <inode> type */
+typedef int64_t xfs_daddr_t; /* <disk address> type */
+typedef char * xfs_caddr_t; /* <core address> type */
+typedef uint32_t xfs_dev_t;
+typedef uint32_t xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_agnumber_t; /* allocation group number */
+typedef int32_t xfs_extnum_t; /* # of extents in a file */
+typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef int64_t xfs_fsize_t; /* bytes in a file */
+typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
+
+typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
+typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
+
+typedef int64_t xfs_lsn_t; /* log sequence number */
+typedef int32_t xfs_tid_t; /* transaction identifier */
+
+typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef uint64_t xfs_dfiloff_t; /* block number in a file */
+typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+
+typedef uint64_t xfs_fileoff_t; /* block number in a file */
+typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define NULLDFSBNO ((xfs_dfsbno_t)-1)
+#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
+#define NULLDRTBNO ((xfs_drtbno_t)-1)
+#define NULLDFILOFF ((xfs_dfiloff_t)-1)
+
+#define NULLFSBLOCK ((xfs_fsblock_t)-1)
+#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
+#define NULLRTBLOCK ((xfs_rtblock_t)-1)
+#define NULLFILEOFF ((xfs_fileoff_t)-1)
+
+#define NULLAGBLOCK ((xfs_agblock_t)-1)
+#define NULLAGNUMBER ((xfs_agnumber_t)-1)
+#define NULLEXTNUM ((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
+#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
+#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS 3
+#define MINABTPTRS 2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN 256
+
+typedef enum {
+ XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+ XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+ XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+ const unsigned char *name;
+ int len;
+};
+
+#endif /* XFS_TYPES_H_ */
diff --git a/libinstaller/syslxfs.h b/libinstaller/syslxfs.h
index 7a23146..4d8f3b2 100644
--- a/libinstaller/syslxfs.h
+++ b/libinstaller/syslxfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Paulo Alcantara <pcacjr at gmail.com>
+ * Copyright 2011-2012 Paulo Alcantara <pcacjr at zytor.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,13 +12,14 @@
#ifndef _SYSLXFS_H_
#define _SYSLXFS_H_
-/* Global fs_type for handling fat, ntfs, ext2/3/4 and btrfs */
+/* Global fs_type for handling fat, ntfs, ext2/3/4, btrfs and xfs */
enum filesystem {
NONE,
EXT2,
BTRFS,
VFAT,
NTFS,
+ XFS,
};
extern int fs_type;
diff --git a/mbr/mbr.S b/mbr/mbr.S
index b71cfb7..270a356 100644
--- a/mbr/mbr.S
+++ b/mbr/mbr.S
@@ -265,6 +265,19 @@ boot:
movl %eax, 8(%si) /* Adjust in-memory partition table entry */
call read_sector
jc disk_error
+
+ /* Check if the read sector is a XFS superblock */
+ cmpl $0x42534658, (bootsec) /* "XFSB" */
+ jne no_xfs
+
+ /* We put the Syslinux boot sector at offset 0x800 (4 sectors), so we
+ * need to adjust %eax (%eax + 4) to read the right sector into 0x7C00.
+ */
+ addl $0x800 >> 0x09, %eax /* plus 4 sectors */
+ call read_sector
+ jc disk_error
+
+no_xfs:
cmpw $0xaa55, (bootsec+510)
jne missing_os /* Not a valid boot sector */
movw $driveno, %sp /* driveno == bootsec-6 */