13984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt/*
23984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * undo_io.c --- This is the undo io manager that copies the old data that
33984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * copies the old data being overwritten into a tdb database
43984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt *
53984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * Copyright IBM Corporation, 2007
63984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
73984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt *
83984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * %Begin-Header%
98558eab78390d1924cd6b255686ceef133f294d5Ken Sumrall * This file may be redistributed under the terms of the GNU Library
108558eab78390d1924cd6b255686ceef133f294d5Ken Sumrall * General Public License, version 2.
113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * %End-Header%
123984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt */
133984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
143984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#define _LARGEFILE_SOURCE
153984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#define _LARGEFILE64_SOURCE
163984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
173984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <stdio.h>
183984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <string.h>
193984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#if HAVE_UNISTD_H
203984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <unistd.h>
213984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#if HAVE_ERRNO_H
233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <errno.h>
243984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
253984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <fcntl.h>
263984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <time.h>
273984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#ifdef __linux__
283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <sys/utsname.h>
293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#if HAVE_SYS_STAT_H
313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <sys/stat.h>
323984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
333984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#if HAVE_SYS_TYPES_H
343984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <sys/types.h>
353984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
363984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#if HAVE_SYS_RESOURCE_H
373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include <sys/resource.h>
383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
393984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
403984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include "tdb.h"
413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
423984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include "ext2_fs.h"
433984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#include "ext2fs.h"
443984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
453984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#ifdef __GNUC__
463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#define ATTR(x) __attribute__(x)
473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#else
483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#define ATTR(x)
493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
503984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
513984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt/*
523984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * For checking structure magic numbers...
533984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt */
543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#define EXT2_CHECK_MAGIC(struct, code) \
563984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	  if ((struct)->magic != (code)) return (code)
573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstruct undo_private_data {
593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	int	magic;
603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	TDB_CONTEXT *tdb;
613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	char *tdb_file;
623984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
633984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/* The backing io channel */
643984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io_channel real;
653984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
663984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	int tdb_data_size;
673984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	int tdb_written;
683984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
693984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/* to support offset in unix I/O manager */
703984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ext2_loff_t offset;
713984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt};
723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
733984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_open(const char *name, int flags, io_channel *channel);
743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_close(io_channel channel);
753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_set_blksize(io_channel channel, int blksize);
763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_read_blk(io_channel channel, unsigned long block,
773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			       int count, void *data);
783984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_write_blk(io_channel channel, unsigned long block,
793984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				int count, const void *data);
803984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_flush(io_channel channel);
813984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_write_byte(io_channel channel, unsigned long offset,
823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				int size, const void *data);
833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_set_option(io_channel channel, const char *option,
843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				 const char *arg);
853984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
863984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic struct struct_io_manager struct_undo_manager = {
873984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_ET_MAGIC_IO_MANAGER,
883984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	"Undo I/O Manager",
893984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_open,
903984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_close,
913984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_set_blksize,
923984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_read_blk,
933984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_write_blk,
943984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_flush,
953984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_write_byte,
963984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_set_option
973984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt};
983984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
993984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtio_manager undo_io_manager = &struct_undo_manager;
1003984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic io_manager undo_io_backing_manager ;
1013984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic char *tdb_file;
1023984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic int actual_size;
1033984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1043984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic unsigned char mtime_key[] = "filesystem MTIME";
1053984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic unsigned char blksize_key[] = "filesystem BLKSIZE";
1063984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic unsigned char uuid_key[] = "filesystem UUID";
1073984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1083984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidterrcode_t set_undo_io_backing_manager(io_manager manager)
1093984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
1103984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
1113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * We may want to do some validation later
1123984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
1133984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_io_backing_manager = manager;
1143984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return 0;
1153984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
1163984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1173984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidterrcode_t set_undo_io_backup_file(char *file_name)
1183984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
1193984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_file = strdup(file_name);
1203984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1213984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (tdb_file == NULL) {
1223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return EXT2_ET_NO_MEMORY;
1233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
1243984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1253984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return 0;
1263984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
1273984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t write_file_system_identity(io_channel undo_channel,
1293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt							TDB_CONTEXT *tdb)
1303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
1313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t retval;
1323984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct ext2_super_block super;
1333984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	TDB_DATA tdb_key, tdb_data;
1343984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
1353984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io_channel channel;
1363984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	int block_size ;
1373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) undo_channel->private_data;
1393984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	channel = data->real;
1403984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	block_size = channel->block_size;
1413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1423984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
1433984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
1443984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
1453984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		goto err_out;
1463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/* Write to tdb file in the file system byte order */
1483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_key.dptr = mtime_key;
1493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_key.dsize = sizeof(mtime_key);
1503984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_data.dptr = (unsigned char *) &(super.s_mtime);
1513984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_data.dsize = sizeof(super.s_mtime);
1523984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1533984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
1543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval == -1) {
1553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
1563984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		goto err_out;
1573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
1583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_key.dptr = uuid_key;
1603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_key.dsize = sizeof(uuid_key);
1613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_data.dptr = (unsigned char *)&(super.s_uuid);
1623984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_data.dsize = sizeof(super.s_uuid);
1633984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1643984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
1653984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval == -1) {
1663984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
1673984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
1683984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1693984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidterr_out:
1703984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io_channel_set_blksize(channel, block_size);
1713984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
1723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
1733984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t write_block_size(TDB_CONTEXT *tdb, int block_size)
1753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
1763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t retval;
1773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	TDB_DATA tdb_key, tdb_data;
1783984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1793984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_key.dptr = blksize_key;
1803984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_key.dsize = sizeof(blksize_key);
1813984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_data.dptr = (unsigned char *)&(block_size);
1823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_data.dsize = sizeof(block_size);
1833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT);
1853984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval == -1) {
1863984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
1873984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
1883984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1893984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
1903984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
1913984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1923984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_write_tdb(io_channel channel,
1933984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				unsigned long block, int count)
1943984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
1953984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
1963984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	int size, sz;
1973984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned long block_num, backing_blk_num;
1983984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t retval = 0;
1993984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ext2_loff_t offset;
2003984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
2013984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	TDB_DATA tdb_key, tdb_data;
2023984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned char *read_ptr;
2033984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned long end_block;
2043984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2053984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
2063984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2073984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->tdb == NULL) {
2083984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		/*
2093984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * Transaction database not initialized
2103984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 */
2113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return 0;
2123984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
2133984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2143984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (count == 1)
2153984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		size = channel->block_size;
2163984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	else {
2173984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (count < 0)
2183984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			size = -count;
2193984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		else
2203984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			size = count * channel->block_size;
2213984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
2223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
2233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * Data is stored in tdb database as blocks of tdb_data_size size
2243984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * This helps in efficient lookup further.
2253984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 *
2263984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * We divide the disk to blocks of tdb_data_size.
2273984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
2283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	offset = (block * channel->block_size) + data->offset ;
2293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	block_num = offset / data->tdb_data_size;
2303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	end_block = (offset + size) / data->tdb_data_size;
2313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2323984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_transaction_start(data->tdb);
2333984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	while (block_num <= end_block ) {
2343984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2353984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		tdb_key.dptr = (unsigned char *)&block_num;
2363984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		tdb_key.dsize = sizeof(block_num);
2373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		/*
2383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * Check if we have the record already
2393984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 */
2403984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (tdb_exists(data->tdb, tdb_key)) {
2413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			/* Try the next block */
2423984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			block_num++;
2433984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			continue;
2443984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		}
2453984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		/*
2463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * Read one block using the backing I/O manager
2473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * The backing I/O manager block size may be
2483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * different from the tdb_data_size.
2493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * Also we need to recalcuate the block number with respect
2503984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 * to the backing I/O manager.
2513984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 */
2523984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		offset = block_num * data->tdb_data_size;
2533984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		backing_blk_num = (offset - data->offset) / channel->block_size;
2543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		count = data->tdb_data_size +
2563984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				((offset - data->offset) % channel->block_size);
2573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = ext2fs_get_mem(count, &read_ptr);
2583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (retval) {
2593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			tdb_transaction_cancel(data->tdb);
2603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return retval;
2613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		}
2623984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
2633984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		memset(read_ptr, 0, count);
2643984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		actual_size = 0;
2653984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if ((count % channel->block_size) == 0)
2663984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			sz = count / channel->block_size;
2673984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		else
2683984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			sz = -count;
2693984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_read_blk(data->real, backing_blk_num,
2703984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt					     sz, read_ptr);
2713984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (retval) {
2723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			if (retval != EXT2_ET_SHORT_READ) {
2733984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				free(read_ptr);
2743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				tdb_transaction_cancel(data->tdb);
2753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				return retval;
2763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			}
2773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			/*
2783984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			 * short read so update the record size
2793984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			 * accordingly
2803984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			 */
2813984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			tdb_data.dsize = actual_size;
2823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		} else {
2833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			tdb_data.dsize = data->tdb_data_size;
2843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		}
2853984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		tdb_data.dptr = read_ptr +
2863984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				((offset - data->offset) % channel->block_size);
2873984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#ifdef DEBUG
2883984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		printf("Printing with key %ld data %x and size %d\n",
2893984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		       block_num,
2903984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		       tdb_data.dptr,
2913984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		       tdb_data.dsize);
2923984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt#endif
2933984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (!data->tdb_written) {
2943984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			data->tdb_written = 1;
2953984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			/* Write the blocksize to tdb file */
2963984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			retval = write_block_size(data->tdb,
2973984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt						  data->tdb_data_size);
2983984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			if (retval) {
2993984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				tdb_transaction_cancel(data->tdb);
3003984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				retval = EXT2_ET_TDB_ERR_IO;
3013984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				free(read_ptr);
3023984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				return retval;
3033984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			}
3043984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		}
3053984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT);
3063984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (retval == -1) {
3073984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			/*
3083984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			 * TDB_ERR_EXISTS cannot happen because we
3093984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			 * have already verified it doesn't exist
3103984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			 */
3113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			tdb_transaction_cancel(data->tdb);
3123984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			retval = EXT2_ET_TDB_ERR_IO;
3133984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			free(read_ptr);
3143984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return retval;
3153984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		}
3163984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		free(read_ptr);
3173984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		/* Next block */
3183984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		block_num++;
3193984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
3203984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	tdb_transaction_commit(data->tdb);
3213984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
3233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
3243984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3253984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_io_read_error(io_channel channel ATTR((unused)),
3263984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				    unsigned long block ATTR((unused)),
3273984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				    int count ATTR((unused)),
3283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				    void *data ATTR((unused)),
3293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				    size_t size ATTR((unused)),
3303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				    int actual,
3313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				    errcode_t error ATTR((unused)))
3323984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
3333984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	actual_size = actual;
3343984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return error;
3353984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
3363984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic void undo_err_handler_init(io_channel channel)
3383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
3393984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	channel->read_error = undo_io_read_error;
3403984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
3413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3423984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_open(const char *name, int flags, io_channel *channel)
3433984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
3443984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io_channel	io = NULL;
3453984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data = NULL;
3463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval;
3473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (name == 0)
3493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return EXT2_ET_BAD_DEVICE_NAME;
3503984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
3513984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
3523984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return retval;
3533984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	memset(io, 0, sizeof(struct struct_io_channel));
3543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
3553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = ext2fs_get_mem(sizeof(struct undo_private_data), &data);
3563984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
3573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		goto cleanup;
3583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->manager = undo_io_manager;
3603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
3613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
3623984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		goto cleanup;
3633984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3643984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	strcpy(io->name, name);
3653984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->private_data = data;
3663984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->block_size = 1024;
3673984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->read_error = 0;
3683984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->write_error = 0;
3693984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	io->refcount = 1;
3703984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3713984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	memset(data, 0, sizeof(struct undo_private_data));
3723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
3733984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (undo_io_backing_manager) {
3753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = undo_io_backing_manager->open(name, flags,
3763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt						       &data->real);
3773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (retval)
3783984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			goto cleanup;
3793984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	} else {
3803984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		data->real = 0;
3813984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
3823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/* setup the tdb file */
3843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data->tdb = tdb_open(tdb_file, 0, TDB_CLEAR_IF_FIRST,
3853984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			     O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
3863984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (!data->tdb) {
3873984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = errno;
3883984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		goto cleanup;
3893984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
3903984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3913984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
3923984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * setup err handler for read so that we know
3933984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * when the backing manager fails do short read
3943984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
3953984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	undo_err_handler_init(data->real);
3963984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
3973984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	*channel = io;
3983984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return 0;
3993984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4003984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtcleanup:
4013984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real)
4023984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		io_channel_close(data->real);
4033984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data)
4043984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		ext2fs_free_mem(&data);
4053984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (io)
4063984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		ext2fs_free_mem(&io);
4073984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
4083984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
4093984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4103984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_close(io_channel channel)
4113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
4123984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
4133984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval = 0;
4143984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4153984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4163984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
4173984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4183984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4193984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (--channel->refcount > 0)
4203984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return 0;
4213984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/* Before closing write the file system identity */
4223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = write_file_system_identity(channel, data->tdb);
4233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
4243984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return retval;
4253984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real)
4263984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_close(data->real);
4273984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->tdb)
4283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		tdb_close(data->tdb);
4293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ext2fs_free_mem(&channel->private_data);
4303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (channel->name)
4313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		ext2fs_free_mem(&channel->name);
4323984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ext2fs_free_mem(&channel);
4333984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4343984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
4353984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
4363984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_set_blksize(io_channel channel, int blksize)
4383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
4393984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
4403984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t		retval = 0;
4413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4423984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4433984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
4443984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4453984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real)
4473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_set_blksize(data->real, blksize);
4483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
4493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * Set the block size used for tdb
4503984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
4513984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (!data->tdb_data_size) {
4523984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		data->tdb_data_size = blksize;
4533984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
4543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	channel->block_size = blksize;
4553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
4563984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
4573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_read_blk(io_channel channel, unsigned long block,
4593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			       int count, void *buf)
4603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
4613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval = 0;
4623984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
4633984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4643984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4653984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
4663984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4673984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4683984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real)
4693984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_read_blk(data->real, block, count, buf);
4703984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4713984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
4723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
4733984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_write_blk(io_channel channel, unsigned long block,
4753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				int count, const void *buf)
4763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
4773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
4783984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval = 0;
4793984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4803984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4813984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
4823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
4843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * First write the existing content into database
4853984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
4863984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = undo_write_tdb(channel, block, count);
4873984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
4883984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		 return retval;
4893984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real)
4903984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_write_blk(data->real, block, count, buf);
4913984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4923984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
4933984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
4943984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
4953984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_write_byte(io_channel channel, unsigned long offset,
4963984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				 int size, const void *buf)
4973984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
4983984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
4993984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval = 0;
5003984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ext2_loff_t	location;
5013984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned long blk_num, count;;
5023984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5033984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5043984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
5053984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5063984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5073984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	location = offset + data->offset;
5083984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	blk_num = location/channel->block_size;
5093984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
5103984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * the size specified may spread across multiple blocks
5113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * also make sure we account for the fact that block start
5123984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * offset for tdb is different from the backing I/O manager
5133984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * due to possible different block size
5143984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
5153984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	count = (size + (location % channel->block_size) +
5163984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			channel->block_size  -1)/channel->block_size;
5173984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	retval = undo_write_tdb(channel, blk_num, count);
5183984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (retval)
5193984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return retval;
5203984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real && data->real->manager->write_byte)
5213984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_write_byte(data->real, offset, size, buf);
5223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
5243984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
5253984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5263984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt/*
5273984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt * Flush data buffers to disk.
5283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt */
5293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_flush(io_channel channel)
5303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
5313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval = 0;
5323984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
5333984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5343984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5353984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
5363984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real)
5393984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = io_channel_flush(data->real);
5403984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
5423984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
5433984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5443984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidtstatic errcode_t undo_set_option(io_channel channel, const char *option,
5453984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt				 const char *arg)
5463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt{
5473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	retval = 0;
5483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	struct undo_private_data *data;
5493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned long tmp;
5503984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	char *end;
5513984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5523984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5533984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	data = (struct undo_private_data *) channel->private_data;
5543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5563984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (!strcmp(option, "tdb_data_size")) {
5573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (!arg)
5583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return EXT2_ET_INVALID_ARGUMENT;
5593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		tmp = strtoul(arg, &end, 0);
5613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (*end)
5623984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return EXT2_ET_INVALID_ARGUMENT;
5633984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (!data->tdb_data_size || !data->tdb_written) {
5643984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			data->tdb_data_size = tmp;
5653984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		}
5663984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return 0;
5673984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
5683984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	/*
5693984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * Need to support offset option to work with
5703984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 * Unix I/O manager
5713984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	 */
5723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (data->real && data->real->manager->set_option) {
5733984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		retval = data->real->manager->set_option(data->real,
5743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt							option, arg);
5753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
5763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (!retval && !strcmp(option, "offset")) {
5773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (!arg)
5783984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return EXT2_ET_INVALID_ARGUMENT;
5793984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5803984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		tmp = strtoul(arg, &end, 0);
5813984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (*end)
5823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return EXT2_ET_INVALID_ARGUMENT;
5833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		data->offset = tmp;
5843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	}
5853984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	return retval;
5863984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt}
587