/*
 * Copyright (C) 2000-2003 ASANO Masahiro
 */

#include "def.h"

#define __KERNEL__
#include <xfs.h>
#include <xfs_inum.h>
#include <xfs_dir.h>
#include <xfs_dir2.h>
#include <xfs_bmap_btree.h>
#include <xfs_attr_sf.h>
#include <xfs_dir_sf.h>
#include <xfs_dir2_sf.h>
#include <xfs_dinode.h>
#include <xfs_inode.h>
#include <xfs_bit.h>

#include "flags_inode.h"

void
prhead_xfs_inode()
{
	mprintf(SPTR"      INO MODE   UID     SIZE "SPTR" "SPTR" PIN UCS FLAGS\n",
		"ADDR", "TRANSP", "ITEMP");
}

addr_t
print_xfs_inode(addr, fflag, rflag)
	addr_t addr;
	int fflag;
	int rflag;
{
	xfs_inode_t i;
	const char *s;
	static const struct bitname iflags[] = {
		{ XFS_IGRIO,	"igrio" },
		{ XFS_IUIOSZ,	"iuiosz" },
		{ XFS_IQUIESCE,	"iquiesce" },
		{ XFS_IRECLAIM,	"ireclaim" },
		{ 0,		NULL }
	};
	static const struct bitname iforkflags[] = {
		{ XFS_IFINLINE,	"inline" },
		{ XFS_IFEXTENTS,"extents" },
		{ XFS_IFBROOT,	"broot" },
		{ 0,		NULL }
	};

	memread(addr, sizeof(i), &i, "xfs_inode_t");

	if (fflag == 0) {
		mprintf(FPTR " %8lx ", addr, (long)i.i_ino);
		mprint_mode(i.i_d.di_mode);
		mprintf(" %5d %8Lx ", i.i_d.di_uid, i.i_d.di_size);
		mprintf(FPTR " " FPTR,  i.i_transp, i.i_itemp);
		mprintf(" %3x  %c%c ", i.i_pincount,
			i.i_update_core? 'C': '-',
			i.i_update_size? 'S': '-');
		mprintbit(iflags, i.i_flags);
		mprintf("\n");
	} else {
		mprintf("addr     " FPTR "  (%x)\n", addr, sizeof(i));

		mprintf("mount    " FPTR "  (xfs_mount)\n", i.i_mount);
		mprintf("ino          %lx\n", (long)i.i_ino);
		mprintf("blkno        %llx\n", (long long)i.i_blkno);
		mprintf("len          %x\n", i.i_len);
		mprintf("boffset      %x\n", i.i_boffset);

		mprintf("afp      " FPTR "\n", i.i_afp);
		mprintf("df.bytes     %x / %x\n", i.i_df.if_bytes,
						  i.i_df.if_real_bytes);
		mprintf("df.broot " FPTR "  (%x)\n", i.i_df.if_broot,
						i.i_df.if_broot_bytes);
		mprintf("df.flags     %x  ", i.i_df.if_flags);
		mprintbit(iforkflags, i.i_df.if_flags);
		mprintf("\n");
		mprintf("df.u1    " FPTR "  (xfs_bmbt_rec)\n", i.i_df.if_u1.if_extents);

		mprintf("transp   " FPTR "  (xfs_trans)\n", i.i_transp);
		mprintf("itemp    " FPTR "  (xfs_log_item)\n", i.i_itemp);
		mprintf("pincount     %x\n", i.i_pincount);
#ifdef _xfs_inode_has_i_refcache
		mprintf("refcache " FPTR "\n", i.i_refcache);
#endif
#ifdef _xfs_inode_has_i_release
		mprintf("release  " FPTR "\n", i.i_release);
#endif

		mprintf("flags        %x ", i.i_flags);
		mprintbit(iflags, i.i_flags);
		mprintf("\n");
		mprintf("update_core  %x\n", i.i_update_core);
		mprintf("update_size  %x\n", i.i_update_size);
		mprintf("gen          %x\n", i.i_gen);
		mprintf("delayed_blks %x\n", i.i_delayed_blks);

		mprintf("d.mode       %x  ", i.i_d.di_mode);
		mprint_mode(i.i_d.di_mode);
		mprintf("\n");
		switch (i.i_d.di_format) {
		case XFS_DINODE_FMT_DEV:	s = "dev";	break;
		case XFS_DINODE_FMT_LOCAL:	s = "local";	break;
		case XFS_DINODE_FMT_EXTENTS:	s = "extents";	break;
		case XFS_DINODE_FMT_BTREE:	s = "btree";	break;
		case XFS_DINODE_FMT_UUID:	s = "uuid";	break;
		default:			s = "?";	break;
		}
		mprintf("d.format     %x  %s\n", i.i_d.di_format, s);
		mprintf("d.uid gid    %d %d\n", i.i_d.di_uid, i.i_d.di_gid);
		mprintf("d.size       %Lx\n", i.i_d.di_size);
		mprintf("d.nextents   %x\n", i.i_d.di_nextents);
		mprintf("d.flags      %x\n", i.i_d.di_flags);
	}

	if (rflag) {
		return (addr_t)i.i_next;
	}
	return (addr_t)i.i_mnext;
}

addr_t
print_xfs_bmbt_rec(addr, size, needswap)
	addr_t addr;
	int size;
	int needswap;
{
	int i, n;
	struct bmbt {
		__u64	l0, l1;
	} bmbt[256];

	mprintf(SPTR "      STARTOFF    STARTBLOCK BLOCKCOUNT STATE\n", "ADDR");

	while (size > 0) {
		n = size;
		if (size < sizeof(bmbt))
			n = size / sizeof(bmbt[0]);
		else
			n = sizeof(bmbt) / sizeof(bmbt[0]);
		memread(addr, n * sizeof(bmbt[0]), bmbt, "xfs_bmbt_rec");
		for (i = 0; i < n; i++) {
			int ext_flag;
			xfs_fileoff_t startoff;
			xfs_fsblock_t startblock;
			xfs_filblks_t blockcount;
			__u64 l0, l1;

			if (!needswap) {
				/* new style */
				l0 = bmbt[i].l0;
				l1 = bmbt[i].l1;
			} else {
				/* old fashon */
				l0 = be64_to_cpup(&bmbt[i].l0);
				l1 = be64_to_cpup(&bmbt[i].l1);
			}
			mprintf(FPTR " ", addr);

			ext_flag = l0 >> (64 - BMBT_EXNTFLAG_BITLEN);
			startoff = (l0 & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
			startblock = (((xfs_fsblock_t)l0 & XFS_MASK64LO(9)) << 43) | (((xfs_fsblock_t)l1) >> 21);
			blockcount = (xfs_filblks_t)(l1 & XFS_MASK64LO(21));

			mprintf("%13llx %13llx %10llx",
				(__u64)startoff, (__u64)startblock,
				(__u64)blockcount);
			mprintf(ext_flag? " unwrittren\n": "\n");

			addr += sizeof(bmbt[0]);
		}
		size -= n * sizeof(bmbt[0]);
	}
	return 0;
}
