void do_refcard(int argc, char *argv[])
{
  FILE *out;

  out = open_pager();
  fprintf(out, "--MODES--\ndirectory -- 0x%x\nregular file -- 0x%x\n",
	  S_IFDIR | 0755, S_IFREG | 0755);
  fprintf(out, "symlink -- 0x%x\nchrdev -- 0x%x\nblkdev -- 0x%x\n\n",
	  S_IFLNK | 0755, S_IFCHR | 0755, S_IFBLK | 0755);
  fprintf(out, "--INODES--\nBad Blocks at 1, Root inode at 2, Bootloader at \
5, First usable inode is 11\n\n");
  fprintf(out, "--BLOCKS--\nSuperblock is block 1\n\n");
  close_pager(out);
}


void write_inode_to_file(ino_t inode, char *filename, int append)
{
	FILE *ifile = NULL;
	struct ext2_inode inode_buf;
	int retval;

	ifile = fopen(filename, append ? "ab" : "wb");
	if (!ifile) {
		com_err("write_inode_to_file", 0, "Cannot open file");
		return;
	}
	retval = ext2fs_read_inode(fs, inode, &inode_buf);
	if (retval) 
	  com_err("write_inode_to_file",retval,"");
	else 
	  fwrite(&inode_buf, 1, sizeof(inode_buf), ifile);

	fclose(ifile);
}


void write_block_to_file(blk_t block, char *filename, int append)
{
	char *blockbuf = NULL;
	FILE *blockfile = NULL;

	blockfile = fopen(filename, append ? "ab" : "wb");
	if (!blockfile) {
		com_err("write_block_to_file", 0, "Cannot open file");
		return;
	}
	blockbuf = malloc(fs->blocksize);

	io_channel_read_blk(fs->io, block, 1, blockbuf);
	fwrite(blockbuf, 1, fs->blocksize, blockfile);

	fclose(blockfile);
	free(blockbuf);
}



void read_block_from_file(blk_t block, char *filename)
{
	char *blockbuf = NULL;
	FILE *blockfile = NULL;

	blockfile = fopen(filename, "rb");
	if (!blockfile) {
		com_err("read_block_from_file", 0, "Cannot open file");
		return;
	}

	blockbuf = malloc(fs->blocksize);

	fread(blockbuf, 1, fs->blocksize, blockfile);
	io_channel_write_blk(fs->io, block, 1, blockbuf);

	fclose(blockfile);
	free(blockbuf);
}


void read_inode_from_file(ino_t inode, char *filename)
{
  	FILE *ifile = NULL;
        struct ext2_inode inode_buf;
	int retval;

	ifile = fopen(filename, "rb");
	if (!ifile) {
		com_err("read_inode_from_file", 0, "Cannot open file");
		return;
	}
	fread(&inode_buf, 1, sizeof(inode_buf), ifile);
	retval = ext2fs_write_inode(fs, inode, &inode_buf);
	if (retval) 
	  com_err("read_inode_from_file",retval,"");

	fclose(ifile);
}


void do_write_inode(int argc, char *argv[])
{
	ino_t inode;

	if (argc < 3) {
		com_err(argv[0], 0, "Usage: write_inode <file> <dest_file> [a]");
		return;
	}
	if (check_fs_open(argv[0]))
		return;
	inode = string_to_inode(argv[1]);
	if (!inode) 
		return;

	write_inode_to_file(inode,argv[2], (argc == 4) && (*argv[3] == 'a'));
}


void do_write_block(int argc, char *argv[])
{
	blk_t	block;

	if (argc < 3) {
		com_err(argv[0], 0, "Usage: write_block <block> <file> [a]");
		return;
	}
	if (check_fs_open(argv[0]))
		return;

	block=strtoul(argv[1], NULL, 0);

	write_block_to_file(block, argv[2], (argc == 4) && (*argv[3] == 'a'));
}


void do_read_block(int argc, char *argv[])
{
	blk_t	block;

	if (argc != 3) {
		com_err(argv[0], 0, "Usage: read_block <block> <file>");
		return;
	}
	if (check_fs_open(argv[0]))
		return;

	block=strtoul(argv[1], NULL, 0);
	read_block_from_file(block, argv[2]);
}


void do_read_inode(int argc, char *argv[])
{
	ino_t inode;

	if (argc != 3) {
		com_err(argv[0], 0, "Usage: read_inode <file> <src_file>");
		return;
	}
	if (check_fs_open(argv[0]))
		return;

	inode = string_to_inode(argv[1]);
	if (!inode) 
		return;

	read_inode_from_file(inode, argv[2]);
}


void do_edit_block(int argc, char *argv[])
{
	blk_t block;
	char tmpname[L_tmpnam+20];
	char sysstring[L_tmpnam+80];
	char *binary_ed;

	if (argc != 2) {
		com_err(argv[0], 0, "Usage: edit_block <block>");
		return;
	}
	if (check_fs_open(argv[0]))
		return;
	block = strtoul(argv[1], NULL, 0);
	tmpnam(tmpname);
	/* XXX - what should we do for the binary editor? */
	binary_ed = getenv("BINARY_EDITOR");
	sprintf(sysstring, "%s %s", binary_ed ? binary_ed : "bpe" , tmpname);
	write_block_to_file(block, tmpname, 0);
	system(sysstring);
	read_block_from_file(block, tmpname);
	unlink(tmpname);
}

void do_edit_inode(int argc, char *argv[])
{
	ino_t inode;
	char tmpname[L_tmpnam+20];
	char sysstring[40+L_tmpnam];

	if (argc != 2) {
		com_err(argv[0], 0, "Usage: edit_inode <file>");
		return;
	}
	if (check_fs_open(argv[0]))
		return;
	inode = string_to_inode(argv[1]);
	if (!inode) 
		return;

   
	tmpnam(tmpname);
	sprintf(sysstring, "bpe %s\n", tmpname);
	write_inode_to_file(inode, tmpname, 0);
	system(sysstring);
	read_inode_from_file(inode, tmpname);
	unlink(tmpname);
}


void hexline(FILE *out, unsigned char *data, int width, int line, int size)
{
	int col;

	fprintf(out, "%08x  ", line*width);
	for (col=0; col < size; col++)
		fprintf(out, "%02x ", *(data++));
	for (col=width-size+4; col > 0; col --)
		fprintf(out," ");
	for (col=0, data -= size; col < size; col++, data++)
		fprintf(out,"%c", isprint(*data) ? *data : '.');
	fprintf(out,"\n");
}

#define MAX_UNPAGED_LINES 20

void hexdump(unsigned char *data, int size)
{
	int width=16, lines=size / width, leftover = size % width;
	int line;
	unsigned char *cur = data;
	FILE *outfile;

	outfile = open_pager();

	for (line=0; line < lines; line++, cur += width)
		hexline(outfile, cur, width, line, width);

	if (leftover) hexline(outfile, cur, width, line, leftover);

	close_pager(outfile);
}

void do_dump_inode(int argc, char *argv[])
{
	struct ext2_inode inode_buf;
	ino_t inode;

	if (argc != 2) {
		com_err(argv[0], 0, "Usage: dump_inode <file>");
		return;
	}
	if (check_fs_open(argv[0]))
		return;

	inode = string_to_inode(argv[1]);
	if (!inode) 
		return;

	ext2fs_read_inode(fs, inode, &inode_buf);
	hexdump((unsigned char *)&inode_buf, sizeof(inode_buf));
}

void do_dump_block(int argc, char *argv[])
{
	blk_t	block;
	ino_t	inode;
	char *blockbuf = NULL;

	if (argc != 2) {
		com_err(argv[0], 0, "Usage: dump_block <block>");
		return;
	}
	inode = string_to_inode(argv[1]);
	if (!inode) 
		return;

	blockbuf = malloc(fs->blocksize);
	io_channel_read_blk(fs->io, block, 1, blockbuf);
	hexdump(blockbuf, fs->blocksize);
	free(blockbuf);
}

