2013-04-03 21:06:27 +02:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
2013-05-08 20:17:07 +02:00
using Duplicati.Library.Main.Volumes ;
2013-04-03 21:06:27 +02:00
2013-05-08 20:17:07 +02:00
namespace Duplicati.Library.Main.Database
2013-04-03 21:06:27 +02:00
{
2013-05-25 16:40:15 +02:00
internal partial class LocalRestoreDatabase
2013-04-03 21:06:27 +02:00
{
private class ExistingFileEnumerable : IEnumerable < IExistingFile >
{
private class ExistingFileEnumerator : IEnumerator < IExistingFile >, IDisposable
{
private class ExistingFile : IExistingFile
{
private class ExistingFileBlockEnumerable : IEnumerable < IExistingFileBlock >
{
private class ExistingFileBlockEnumerator : IEnumerator < IExistingFileBlock >
{
private class ExistingFileBlock : IExistingFileBlock
{
private System . Data . IDataReader m_reader ;
public ExistingFileBlock ( System . Data . IDataReader reader )
{
m_reader = reader ;
}
public string Hash
{
get
{
2013-06-01 14:22:10 +02:00
var v = m_reader . GetValue ( 4 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
public long Index
{
get
{
2013-06-01 14:22:10 +02:00
var v = m_reader . GetValue ( 5 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public long Size
{
get
{
2013-06-01 14:22:10 +02:00
var v = m_reader . GetValue ( 6 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
}
private System . Data . IDataReader m_reader ;
private ExistingFile m_file ;
private ExistingFileBlock m_block ;
private string m_current ;
public ExistingFileBlockEnumerator ( System . Data . IDataReader reader , ExistingFile file )
{
m_reader = reader ;
m_file = file ;
this . Reset ();
}
public IExistingFileBlock Current
{
get
{
return m_block ;
}
}
public void Dispose ()
{
}
object System . Collections . IEnumerator . Current
{
get { return this . Current ; }
}
public bool MoveNext ()
{
if (! m_file . HasMoreData )
return false ;
if ( m_current == null )
m_current = m_file . TargetPath ;
else
m_file . HasMoreData = m_reader . Read ();
if ( m_file . HasMoreData && m_current != m_file . TargetPath )
return false ;
return m_file . HasMoreData ;
}
public void Reset ()
{
m_block = new ExistingFileBlock ( m_reader );
m_current = null ;
}
}
private System . Data . IDataReader m_reader ;
private ExistingFile m_file ;
public ExistingFileBlockEnumerable ( System . Data . IDataReader reader , ExistingFile file )
{
m_reader = reader ;
m_file = file ;
}
public IEnumerator < IExistingFileBlock > GetEnumerator ()
{
return new ExistingFileBlockEnumerator ( m_reader , m_file );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
private System . Data . IDataReader m_reader ;
public bool HasMoreData { get ; set ; }
public ExistingFile ( System . Data . IDataReader reader )
{
m_reader = reader ;
HasMoreData = m_reader . Read ();
}
public string TargetPath
{
get
{
var v = m_reader . GetValue ( 0 );
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
2013-04-27 10:20:15 +02:00
2013-06-01 14:22:10 +02:00
public string TargetHash
2013-04-27 10:20:15 +02:00
{
get
{
var v = m_reader . GetValue ( 1 );
2013-06-01 14:22:10 +02:00
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
public long TargetFileID
{
get
{
var v = m_reader . GetValue ( 2 );
2013-04-27 10:20:15 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
2013-04-03 21:06:27 +02:00
public long Length
{
get
{
2013-06-01 14:22:10 +02:00
var v = m_reader . GetValue ( 3 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public IEnumerable < IExistingFileBlock > Blocks
{
get { return new ExistingFileBlockEnumerable ( m_reader , this ); }
}
}
private System . Data . IDbCommand m_command ;
private System . Data . IDataReader m_reader ;
private System . Data . IDbConnection m_connection ;
private string m_tablename ;
private ExistingFile m_file ;
private string m_current ;
public ExistingFileEnumerator ( System . Data . IDbConnection con , string tablename )
{
m_connection = con ;
m_tablename = tablename ;
this . Reset ();
}
public void Dispose ()
{
if ( m_reader != null )
{
m_reader . Dispose ();
m_reader = null ;
}
if ( m_command != null )
{
m_command . Dispose ();
m_command = null ;
}
}
public IExistingFile Current
{
get { return m_file ; }
}
object System . Collections . IEnumerator . Current
{
get { return m_file ; }
}
public bool MoveNext ()
{
if ( m_current != null )
{
while ( m_file . HasMoreData && m_file . TargetPath == m_current )
m_file . HasMoreData = m_reader . Read ();
}
m_current = m_file . HasMoreData ? m_file . TargetPath : null ;
return m_file . HasMoreData ;
}
public void Reset ()
{
m_file = null ;
m_command = m_connection . CreateCommand ();
2013-06-01 14:22:10 +02:00
m_command . CommandText = string . Format ( @"SELECT ""{0}"".""TargetPath"", ""Blockset"".""FullHash"", ""{0}"".""ID"", ""Blockset"".""Length"", ""Block"".""Hash"", ""BlocksetEntry"".""Index"", ""Block"".""Size"" FROM ""{0}"", ""Blockset"", ""BlocksetEntry"", ""Block"" WHERE ""{0}"".""BlocksetID"" = ""Blockset"".""ID"" AND ""BlocksetEntry"".""BlocksetID"" = ""{0}"".""BlocksetID"" AND ""BlocksetEntry"".""BlockID"" = ""Block"".""ID"" ORDER BY ""{0}"".""TargetPath"", ""BlocksetEntry"".""Index""" , m_tablename );
2013-04-03 21:06:27 +02:00
m_reader = m_command . ExecuteReader ();
m_file = new ExistingFile ( m_reader );
m_current = null ;
}
}
private System . Data . IDbConnection m_connection ;
private string m_tablename ;
public ExistingFileEnumerable ( System . Data . IDbConnection connection , string tablename )
{
m_connection = connection ;
m_tablename = tablename ;
}
public IEnumerator < IExistingFile > GetEnumerator ()
{
return new ExistingFileEnumerator ( m_connection , m_tablename );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
private class LocalBlockSourceEnumerable : IEnumerable < ILocalBlockSource >
{
private class LocalBlockSourceEnumerator : IEnumerator < ILocalBlockSource >
{
private class LocalBlockSource : ILocalBlockSource
{
private class BlockDescriptorEnumerable : IEnumerable < IBlockDescriptor >
{
private class BlockDescriptorEnumerator : IEnumerator < IBlockDescriptor >
{
private class BlockDescriptor : IBlockDescriptor
{
private class BlockSourceEnumerable : IEnumerable < IBlockSource >
{
private class BlockSourceEnumerator : IEnumerator < IBlockSource >
{
private class BlockSource : IBlockSource
{
private System . Data . IDataReader m_reader ;
public BlockSource ( System . Data . IDataReader reader )
{
m_reader = reader ;
}
public string Path
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 6 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
public long Offset
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 7 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public long Size
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 8 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
}
private System . Data . IDataReader m_reader ;
private LocalBlockSource m_localsource ;
private BlockSource m_source ;
private BlockDescriptor m_descriptor ;
private string m_currenthash ;
private string m_currentfile ;
public BlockSourceEnumerator ( System . Data . IDataReader reader , LocalBlockSource localsource , BlockDescriptor descriptor )
{
m_reader = reader ;
m_localsource = localsource ;
m_descriptor = descriptor ;
this . Reset ();
}
public IBlockSource Current
{
get { return m_source ; }
}
public void Dispose ()
{
}
object System . Collections . IEnumerator . Current
{
get { return this . Current ; }
}
public bool MoveNext ()
{
if (! m_localsource . HasMoreData )
return false ;
if ( m_currenthash != null )
m_localsource . HasMoreData = m_reader . Read ();
if (! m_localsource . HasMoreData )
return false ;
if ( m_currenthash != null && m_currentfile != null )
if ( m_currentfile != m_localsource . TargetPath || m_currenthash != m_descriptor . Hash )
return false ;
m_currenthash = m_descriptor . Hash ;
m_currentfile = m_localsource . TargetPath ;
return m_localsource . HasMoreData ;
}
public void Reset ()
{
m_source = new BlockSource ( m_reader );
m_currenthash = null ;
m_currentfile = null ;
}
}
private System . Data . IDataReader m_reader ;
private LocalBlockSource m_localsource ;
private BlockDescriptor m_descriptor ;
public BlockSourceEnumerable ( System . Data . IDataReader reader , LocalBlockSource localsource , BlockDescriptor descriptor )
{
m_reader = reader ;
m_localsource = localsource ;
m_descriptor = descriptor ;
}
public IEnumerator < IBlockSource > GetEnumerator ()
{
return new BlockSourceEnumerator ( m_reader , m_localsource , m_descriptor );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
private System . Data . IDataReader m_reader ;
private LocalBlockSource m_localsource ;
public BlockDescriptor ( System . Data . IDataReader reader , LocalBlockSource localsource )
{
m_reader = reader ;
m_localsource = localsource ;
}
public string Hash
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 2 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
public long Offset
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 3 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public long Index
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 4 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public long Size
{
get
{
2013-04-27 10:20:15 +02:00
var v = m_reader . GetValue ( 5 );
2013-04-03 21:06:27 +02:00
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public IEnumerable < IBlockSource > Blocksources
{
get { return new BlockSourceEnumerable ( m_reader , m_localsource , this ); }
}
}
private System . Data . IDataReader m_reader ;
private LocalBlockSource m_localsource ;
private BlockDescriptor m_descriptor ;
private string m_currenthash ;
private string m_currentfile ;
public BlockDescriptorEnumerator ( System . Data . IDataReader reader , LocalBlockSource localsource )
{
m_reader = reader ;
m_localsource = localsource ;
this . Reset ();
}
public IBlockDescriptor Current
{
get { return m_descriptor ; }
}
public void Dispose ()
{
}
object System . Collections . IEnumerator . Current
{
get { return this . Current ; }
}
public bool MoveNext ()
{
if (! m_localsource . HasMoreData )
return false ;
if ( m_currenthash != null )
{
while ( m_localsource . HasMoreData && m_currenthash == m_descriptor . Hash && m_currentfile == m_localsource . TargetPath )
m_localsource . HasMoreData = m_reader . Read ();
if ( m_currentfile != m_localsource . TargetPath )
return false ;
}
m_currenthash = m_localsource . HasMoreData ? m_descriptor . Hash : null ;
m_currentfile = m_localsource . HasMoreData ? m_localsource . TargetPath : null ;
return m_localsource . HasMoreData && m_currenthash == m_descriptor . Hash ;
}
public void Reset ()
{
m_descriptor = new BlockDescriptor ( m_reader , m_localsource );
m_currenthash = null ;
m_currentfile = null ;
}
}
private System . Data . IDataReader m_reader ;
private LocalBlockSource m_localsource ;
public BlockDescriptorEnumerable ( System . Data . IDataReader reader , LocalBlockSource localsource )
{
m_reader = reader ;
m_localsource = localsource ;
}
public IEnumerator < IBlockDescriptor > GetEnumerator ()
{
return new BlockDescriptorEnumerator ( m_reader , m_localsource );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
private System . Data . IDataReader m_reader ;
public bool HasMoreData { get ; set ; }
public LocalBlockSource ( System . Data . IDataReader reader )
{
m_reader = reader ;
HasMoreData = reader . Read ();
}
public string TargetPath
{
get
{
var v = m_reader . GetValue ( 0 );
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
2013-04-27 10:20:15 +02:00
public long TargetFileID
{
get
{
var v = m_reader . GetValue ( 1 );
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
2013-04-03 21:06:27 +02:00
public IEnumerable < IBlockDescriptor > Blocks
{
get { return new BlockDescriptorEnumerable ( m_reader , this ); }
}
}
private System . Data . IDbCommand m_command ;
private System . Data . IDataReader m_reader ;
private System . Data . IDbConnection m_connection ;
private LocalBlockSource m_localsource ;
private string m_filetablename ;
private string m_blocktablename ;
private string m_current ;
private long m_blocksize ;
public LocalBlockSourceEnumerator ( System . Data . IDbConnection connection , string filetablename , string blocktablename , long blocksize )
{
m_connection = connection ;
m_filetablename = filetablename ;
m_blocktablename = blocktablename ;
m_blocksize = blocksize ;
this . Reset ();
}
public ILocalBlockSource Current
{
get { return m_localsource ; }
}
public void Dispose ()
{
if ( m_reader != null )
{
m_reader . Dispose ();
m_reader = null ;
}
if ( m_command != null )
{
m_command . Dispose ();
m_command = null ;
}
}
object System . Collections . IEnumerator . Current
{
get { throw new NotImplementedException (); }
}
public bool MoveNext ()
{
if (! m_localsource . HasMoreData )
return false ;
if ( m_current != null )
{
while ( m_localsource . HasMoreData && m_current == m_localsource . TargetPath )
m_localsource . HasMoreData = m_reader . Read ();
}
m_current = m_localsource . HasMoreData ? m_localsource . TargetPath : null ;
return m_localsource . HasMoreData ;
}
public void Reset ()
{
m_command = m_connection . CreateCommand ();
2013-04-27 10:20:15 +02:00
m_command . CommandText = string . Format ( @"SELECT DISTINCT ""A"".""TargetPath"", ""A"".""ID"", ""B"".""Hash"", (""B"".""Index"" * {2}), ""B"".""Index"", ""B"".""Size"", ""C"".""Path"", (""D"".""Index"" * {2}), ""E"".""Size"" FROM ""{0}"" ""A"", ""{1}"" ""B"", ""File"" ""C"", ""BlocksetEntry"" ""D"", ""Block"" E WHERE ""A"".""ID"" = ""B"".""FileID"" AND ""C"".""BlocksetID"" = ""D"".""BlocksetID"" AND ""D"".""BlockID"" = ""E"".""ID"" AND ""B"".""Hash"" = ""E"".""Hash"" AND ""B"".""Size"" = ""E"".""Size"" AND ""B"".""Restored"" = 0 " , m_filetablename , m_blocktablename , m_blocksize );
2013-04-03 21:06:27 +02:00
m_reader = m_command . ExecuteReader ();
m_current = null ;
m_localsource = new LocalBlockSource ( m_reader );
}
}
private System . Data . IDbConnection m_connection ;
private string m_filetablename ;
private string m_blocktablename ;
private long m_blocksize ;
public LocalBlockSourceEnumerable ( System . Data . IDbConnection connection , string filetablename , string blocktablename , long blocksize )
{
m_connection = connection ;
m_filetablename = filetablename ;
m_blocktablename = blocktablename ;
m_blocksize = blocksize ;
}
public IEnumerator < ILocalBlockSource > GetEnumerator ()
{
return new LocalBlockSourceEnumerator ( m_connection , m_filetablename , m_blocktablename , m_blocksize );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
private class VolumePatchEnumerable : IEnumerable < IVolumePatch >
{
private class VolumePatchEnumerator : IEnumerator < IVolumePatch >
{
private class VolumePatch : IVolumePatch
{
private class PatchBlockEnumerable : IEnumerable < IPatchBlock >
{
private class PatchBlockEnumerator : IEnumerator < IPatchBlock >
{
private class PatchBlock : IPatchBlock
{
private System . Data . IDataReader m_reader ;
public PatchBlock ( System . Data . IDataReader reader )
{
m_reader = reader ;
}
public long Offset
{
get
{
var v = m_reader . GetValue ( 1 );
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public long Size
{
get
{
var v = m_reader . GetValue ( 2 );
if ( v == null || v == DBNull . Value )
return - 1 ;
return Convert . ToInt64 ( v );
}
}
public string Key
{
get
{
var v = m_reader . GetValue ( 3 );
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
}
private System . Data . IDataReader m_reader ;
private VolumePatch m_patch ;
private PatchBlock m_block ;
private string m_currentfile ;
private bool m_first ;
public PatchBlockEnumerator ( System . Data . IDataReader reader , VolumePatch patch )
{
m_reader = reader ;
m_patch = patch ;
m_currentfile = patch . Path ;
this . Reset ();
}
public IPatchBlock Current
{
get { return m_block ; }
}
public void Dispose ()
{
}
object System . Collections . IEnumerator . Current
{
get { return this . Current ; }
}
public bool MoveNext ()
{
if (! m_patch . HasMoreData )
return false ;
if ( m_first )
m_first = false ;
else
m_patch . HasMoreData = m_reader . Read ();
var more = m_patch . HasMoreData && m_currentfile == m_patch . Path ;
return more ;
}
public void Reset ()
{
m_block = new PatchBlock ( m_reader );
m_first = true ;
}
}
private System . Data . IDataReader m_reader ;
private VolumePatch m_patch ;
public PatchBlockEnumerable ( System . Data . IDataReader reader , VolumePatch patch )
{
m_reader = reader ;
m_patch = patch ;
}
public IEnumerator < IPatchBlock > GetEnumerator ()
{
return new PatchBlockEnumerator ( m_reader , m_patch );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
private System . Data . IDataReader m_reader ;
public bool HasMoreData { get ; set ; }
public VolumePatch ( System . Data . IDataReader reader )
{
m_reader = reader ;
}
public string Path
{
get
{
var v = m_reader . GetValue ( 0 );
if ( v == null || v == DBNull . Value )
return null ;
return v . ToString ();
}
}
public IEnumerable < IPatchBlock > Blocks
{
get { return new PatchBlockEnumerable ( m_reader , this ); }
}
}
private System . Data . IDbConnection m_connection ;
private System . Data . IDataReader m_reader ;
private System . Data . IDbCommand m_command ;
private string m_filetablename ;
private string m_blocktablename ;
private BlockVolumeReader m_curvolume ;
private VolumePatch m_patch ;
private string m_current = null ;
private string m_tmptable = null ;
private long m_blocksize ;
public VolumePatchEnumerator ( System . Data . IDbConnection connection , string filetablename , string blocktablename , long blocksize , BlockVolumeReader curvolume )
{
m_connection = connection ;
m_filetablename = filetablename ;
m_blocktablename = blocktablename ;
m_curvolume = curvolume ;
m_blocksize = blocksize ;
this . Reset ();
}
public IVolumePatch Current
{
get { return m_patch ; }
}
public void Dispose ()
{
if ( m_reader != null )
{
m_reader . Dispose ();
m_reader = null ;
}
if ( m_command != null )
{
m_command . Dispose ();
m_command = null ;
}
if ( m_tmptable != null )
{
using ( var c = m_connection . CreateCommand ())
{
c . CommandText = string . Format ( @"DROP TABLE ""{0}""" , m_tmptable );
c . ExecuteNonQuery ();
m_tmptable = null ;
}
}
}
object System . Collections . IEnumerator . Current
{
get { return this . Current ; }
}
public bool MoveNext ()
{
if (! m_patch . HasMoreData )
return false ;
if ( m_current != null )
{
while ( m_patch . HasMoreData && m_current == m_patch . Path )
m_patch . HasMoreData = m_reader . Read ();
}
m_current = m_patch . Path ;
return m_patch . HasMoreData ;
}
public void Reset ()
{
this . Dispose ();
using ( var c = m_connection . CreateCommand ())
{
2013-05-08 21:29:59 +02:00
var tablename = "VolumeFiles-" + Library . Utility . Utility . ByteArrayAsHexString ( Guid . NewGuid (). ToByteArray ());
2013-04-03 21:06:27 +02:00
c . CommandText = string . Format ( @"CREATE TEMPORARY TABLE ""{0}"" ( ""Hash"" TEXT NOT NULL, ""Size"" INTEGER NOT NULL )" , tablename );
c . ExecuteNonQuery ();
m_tmptable = tablename ;
c . CommandText = string . Format ( @"INSERT INTO ""{0}"" (""Hash"", ""Size"") VALUES (?,?)" , m_tmptable );
c . AddParameters ( 2 );
foreach ( var s in m_curvolume . Blocks )
{
c . SetParameterValue ( 0 , s . Key );
c . SetParameterValue ( 1 , s . Value );
c . ExecuteNonQuery ();
}
}
m_command = m_connection . CreateCommand ();
m_command . CommandText = string . Format ( @"SELECT DISTINCT ""A"".""TargetPath"", (""B"".""Index"" * {3}), ""B"".""Size"", ""C"".""Hash"" FROM ""{0}"" A, ""{1}"" B, ""{2}"" C WHERE ""A"".""ID"" = ""B"".""FileID"" AND ""B"".""Hash"" = ""C"".""Hash"" AND ""B"".""Size"" = ""C"".""Size"" AND ""B"".""Restored"" = 0 ORDER BY ""A"".""TargetPath"", ""B"".""Index""" , m_filetablename , m_blocktablename , m_tmptable , m_blocksize );
m_reader = m_command . ExecuteReader ();
m_patch = new VolumePatch ( m_reader );
m_patch . HasMoreData = m_reader . Read ();
m_current = null ;
}
}
private System . Data . IDbConnection m_connection ;
private string m_filetablename ;
private string m_blocktablename ;
private BlockVolumeReader m_curvolume ;
private long m_blocksize ;
public VolumePatchEnumerable ( System . Data . IDbConnection connection , string filetablename , string blocktablename , long blocksize , BlockVolumeReader curvolume )
{
m_connection = connection ;
m_filetablename = filetablename ;
m_blocktablename = blocktablename ;
m_blocksize = blocksize ;
m_curvolume = curvolume ;
}
public IEnumerator < IVolumePatch > GetEnumerator ()
{
return new VolumePatchEnumerator ( m_connection , m_filetablename , m_blocktablename , m_blocksize , m_curvolume );
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ()
{
return this . GetEnumerator ();
}
}
2013-05-21 21:11:28 +02:00
}
2013-04-03 21:06:27 +02:00
}