void TurnSnapshotIntoBaselinePrivate(VolumeSnapshotDirectory parentDir, ref List <VolumeSnapshotRevision> revisionsThatCanBeRemoved)
        {
            VolumeSnapshotRevision currentRevision = parentDir.Snapshot.Revision;

            foreach (VolumeSnapshotFile file in parentDir.Files)
            {
                if (file.Revision.Value < currentRevision.Value)
                {
                    revisionsThatCanBeRemoved.Add(file.Revision);

                    // file is older than current snapshot, copy it into the current snapshot
                    // Use Move for speed - the file will be deleted in the next step anyway and
                    // will no longer be needed
                    mArchive.MoveFileFromRevision(file.Revision, currentRevision, file.RelativePath);

                    // update revision id in .xml file
                    file.Revision = currentRevision;
                }
            }

            foreach (VolumeSnapshotDirectory dir in parentDir.Directories)
            {
                if (dir.Revision.Value < currentRevision.Value)
                {
                    dir.Revision = currentRevision;
                }
                TurnSnapshotIntoBaselinePrivate(dir, ref revisionsThatCanBeRemoved);
            }
        }
        private bool CopyAll(VolumeSnapshotDirectory directory)
        {
            directory.Revision = directory.Snapshot.Revision;
            mArchive.CreateDirectory(directory.Snapshot.Revision, directory.RelativePath);

            if (!mOperation.CanContinue)
            {
                return(false);
            }

            foreach (VolumeSnapshotFile fileEntry in directory.Files)
            {
                CopyFileToBackup(fileEntry);

                if (!mOperation.CanContinue)
                {
                    return(false);
                }
            }

            foreach (VolumeSnapshotDirectory dirEntry in directory.Directories)
            {
                if (!CopyAll(dirEntry) || !mOperation.CanContinue)
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 3
0
        public VolumeSnapshotFile GetSubFile(string path)
        {
            VolumeSnapshotDirectory curDir = mRoot;

            string[] dirnames = path.Split(PWLib.Platform.Windows.Path.DirectorySeparatorChar);

            for (int index = 0; index < dirnames.Length - 1; ++index)
            {
                string dirname = dirnames[index];
                if (dirname.Length > 0)
                {
                    VolumeSnapshotDirectory newCurDir = curDir.FindDirectory(dirname);
                    if (newCurDir == null)
                    {
                        return(null);
                    }
                    else
                    {
                        curDir = newCurDir;
                    }
                }
            }

            return(curDir.FindFile(dirnames[dirnames.Length - 1]));
        }
        public void Restore(VolumeSnapshot snapshot, BaseArchive archive, string onDiskPath)
        {
            mOperation.Reset();

            mFileTotalCount        = 0;
            mFilesTotalSize        = 0;
            mFileRunningCount      = 0;
            mFilesTotalSizeRunning = 0;

            try
            {
                mBusy = true;

                VolumeSnapshotDirectory vsd = snapshot.Root;
                mFileTotalCount = vsd.CountAllFiles(ref mFilesTotalSize);

                if (!mOperation.CanContinue)
                {
                    return;
                }

                int relativePathStartIndex = vsd.RelativePath.LastIndexOf(PWLib.Platform.Windows.Path.DirectorySeparatorChar);
                if (relativePathStartIndex < 0)
                {
                    relativePathStartIndex = 0;
                }
                ProcessDirectoryRestore(vsd, archive, relativePathStartIndex, onDiskPath);
            }
            finally
            {
                mBusy = false;
            }
        }
Exemplo n.º 5
0
        private VolumeSnapshot( VolumeSource source, XmlNode parentNode )
        {
            mRevision = VolumeSnapshotRevision.Create( PWLib.XmlHelp.GetAttribute( parentNode, VolumeSnapshotXml.XmlRevisionElement, "" ) );
            if ( mRevision == null )
                throw new Exception( "Could not read revision from snapshot xml '" + parentNode.Name + "'" );

            mRoot = VolumeSnapshotDirectory.BuildFromXml( this, PWLib.XmlHelp.GetFirstChildWithName( parentNode, "directory" ) );
            mFileCount = mRoot.CountAllFiles( ref mTotalFileSize );
        }
Exemplo n.º 6
0
        private VolumeSnapshot(VolumeSource source, XmlNode parentNode)
        {
            mRevision = VolumeSnapshotRevision.Create(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlRevisionElement, ""));
            if (mRevision == null)
            {
                throw new Exception("Could not read revision from snapshot xml '" + parentNode.Name + "'");
            }

            mRoot      = VolumeSnapshotDirectory.BuildFromXml(this, PWLib.XmlHelp.GetFirstChildWithName(parentNode, "directory"));
            mFileCount = mRoot.CountAllFiles(ref mTotalFileSize);
        }
 public void OnDirectoryTheSame(VolumeSnapshotDirectory oldDirectory, VolumeSnapshotDirectory newDirectory)
 {
     mDirectoriesTheSame++;
     if (mInvokeCallbacks)
     {
         if (DirectoryTheSame != null)
         {
             DirectoryTheSame(oldDirectory, newDirectory);
         }
     }
 }
Exemplo n.º 8
0
 public override bool Equals(object obj)
 {
     if (obj is VolumeSnapshotDirectory)
     {
         VolumeSnapshotDirectory rhs = (VolumeSnapshotDirectory)obj;
         return(string.Compare(rhs.mName, this.mName, true) == 0);
     }
     else
     {
         return(false);
     }
 }
        private void ProcessDirectoryRestore(VolumeSnapshotDirectory sourceDir, BaseArchive archive, int relativePathStartIndex, string targetDir)
        {
            if (!mOperation.CanContinue)
            {
                return;
            }

            PWLib.Platform.Windows.Directory.CreateDirectory(targetDir);

            foreach (VolumeSnapshotFile fileEntry in sourceDir.Files)
            {
                try
                {
                    string outDir = targetDir + fileEntry.RelativePath.Substring(relativePathStartIndex);
                    archive.RestoreFile(fileEntry.Revision, fileEntry.RelativePath, outDir, new ArchiveFileDelegate(Restore_ArchiveStoreFile), fileEntry);

                    ulong runningSize = mFilesTotalSizeRunning + fileEntry.FileSize;
                    if (runningSize > mFilesTotalSize)
                    {
                        runningSize = mFilesTotalSize;
                    }
                    if (Progress != null)
                    {
                        Progress(mFileRunningCount + 1, mFileTotalCount, runningSize, mFilesTotalSize);
                    }
                }
                catch (System.Exception e)
                {
                    if (Error != null)
                    {
                        Error("Restore file failed '" + fileEntry.RelativePath + "'", e);
                    }
                }

                if (!mOperation.CanContinue)
                {
                    return;
                }

                mFileRunningCount++;
                mFilesTotalSizeRunning += fileEntry.FileSize;
            }

            foreach (VolumeSnapshotDirectory directoryEntry in sourceDir.Directories)
            {
                ProcessDirectoryRestore(directoryEntry, archive, relativePathStartIndex, targetDir);
                if (!mOperation.CanContinue)
                {
                    return;
                }
            }
        }
        public void OnDirectoryCreated(VolumeSnapshotDirectory newDirectory)
        {
            mDirectoriesCreated++;
            mIsModified = true;
            ulong numNewFilesInDir = newDirectory.CountAllFiles(ref mTotalFileSize);

            mFileCount    += numNewFilesInDir;
            mFilesCreated += numNewFilesInDir;
            if (mInvokeCallbacks)
            {
                if (DirectoryCreated != null)
                {
                    DirectoryCreated(null, newDirectory);
                }
            }
        }
        void UpdateSnapshotToReflectBaselineRevisionPrivate(VolumeSnapshotDirectory parentDir, VolumeSnapshotRevision newRevision)
        {
            foreach (VolumeSnapshotFile file in parentDir.Files)
            {
                if (file.Revision.Value < newRevision.Value)
                {
                    file.Revision = newRevision;
                }
            }

            foreach (VolumeSnapshotDirectory dir in parentDir.Directories)
            {
                if (dir.Revision.Value < newRevision.Value)
                {
                    dir.Revision = newRevision;
                }
                UpdateSnapshotToReflectBaselineRevisionPrivate(dir, newRevision);
            }
        }
Exemplo n.º 12
0
        private VolumeSnapshotDirectory(VolumeSnapshot snapshot, XmlNode parentNode)
        {
            mSnapshot     = snapshot;
            mName         = PWLib.XmlHelp.DirtyString(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlNameElement, ""));
            mRelativePath = PWLib.XmlHelp.DirtyString(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlRelativePathElement, ""));
            mRevision     = VolumeSnapshotRevision.Create(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlRevisionElement, ""));

            long ticks;

            if (long.TryParse(PWLib.XmlHelp.GetAttribute(parentNode, VolumeSnapshotXml.XmlLastModifiedElement, "0"), out ticks))
            {
                mLastModified = new DateTime(ticks);
            }

            foreach (XmlNode childNode in parentNode.ChildNodes)
            {
                string lowerName = childNode.Name.ToLower();
                if (lowerName == VolumeSnapshotXml.XmlDirectoryElement)                   // Sub directories
                {
                    try
                    {
                        VolumeSnapshotDirectory subDirEntry = new VolumeSnapshotDirectory(mSnapshot, childNode);
                        mDirectories.Add(subDirEntry);
                    }
                    catch (System.Exception e)
                    {
                        FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromXml failed in directory '" + mName + "' '" + mRelativePath + "'", e);
                    }
                }
                else if (lowerName == VolumeSnapshotXml.XmlFileElement)                   // Files
                {
                    try
                    {
                        VolumeSnapshotFile fileEntry = VolumeSnapshotFile.BuildFromXml(mSnapshot, childNode);
                        mFiles.Add(fileEntry);
                    }
                    catch (System.Exception e)
                    {
                        FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromXml failed in directory on a file '" + mName + "' '" + mRelativePath + "'", e);
                    }
                }
            }
        }
Exemplo n.º 13
0
        // Takes a full path to a sub directory and tries to find it
        public VolumeSnapshotDirectory GetSubDirectory(string directory)
        {
            VolumeSnapshotDirectory curDir = mRoot;

            foreach (string dirname in directory.Split(PWLib.Platform.Windows.Path.DirectorySeparatorChar))
            {
                if (dirname.Length > 0)
                {
                    VolumeSnapshotDirectory newCurDir = curDir.FindDirectory(dirname);
                    if (newCurDir == null)
                    {
                        return(null);
                    }
                    else
                    {
                        curDir = newCurDir;
                    }
                }
            }
            return(curDir);
        }
        private VolumeSnapshotDirectory( VolumeSnapshot snapshot, XmlNode parentNode )
        {
            mSnapshot = snapshot;
            mName = PWLib.XmlHelp.DirtyString( PWLib.XmlHelp.GetAttribute( parentNode, VolumeSnapshotXml.XmlNameElement, "" ) );
            mRelativePath = PWLib.XmlHelp.DirtyString( PWLib.XmlHelp.GetAttribute( parentNode, VolumeSnapshotXml.XmlRelativePathElement, "" ) );
            mRevision = VolumeSnapshotRevision.Create( PWLib.XmlHelp.GetAttribute( parentNode, VolumeSnapshotXml.XmlRevisionElement, "" ) );

            long ticks;
            if ( long.TryParse( PWLib.XmlHelp.GetAttribute( parentNode, VolumeSnapshotXml.XmlLastModifiedElement, "0" ), out ticks ) )
                mLastModified = new DateTime( ticks );

            foreach ( XmlNode childNode in parentNode.ChildNodes )
            {
                string lowerName = childNode.Name.ToLower();
                if ( lowerName == VolumeSnapshotXml.XmlDirectoryElement ) // Sub directories
                {
                    try
                    {
                        VolumeSnapshotDirectory subDirEntry = new VolumeSnapshotDirectory( mSnapshot, childNode );
                        mDirectories.Add( subDirEntry );
                    }
                    catch ( System.Exception e )
                    {
                        FileSync.__LogError( this, "VolumeSnapshotDirectory.BuildFromXml failed in directory '" + mName + "' '" + mRelativePath + "'", e );
                    }
                }
                else if ( lowerName == VolumeSnapshotXml.XmlFileElement ) // Files
                {
                    try
                    {
                        VolumeSnapshotFile fileEntry = VolumeSnapshotFile.BuildFromXml( mSnapshot, childNode );
                        mFiles.Add( fileEntry );
                    }
                    catch ( System.Exception e )
                    {
                        FileSync.__LogError( this, "VolumeSnapshotDirectory.BuildFromXml failed in directory on a file '" + mName + "' '" + mRelativePath + "'", e );
                    }
                }
            }
        }
Exemplo n.º 15
0
        private VolumeSnapshotDirectory(VolumeSnapshot snapshot, VolumeSource source, string relativePath)
        {
            mSnapshot     = snapshot;
            mRelativePath = relativePath;
            mName         = mRelativePath.Length <= 1 ? "" : PWLib.Platform.Windows.Path.GetLeafName(relativePath);
            mLastModified = source.GetLastWriteTimeUtc(relativePath);              // PWLib.Platform.Windows.Directory.GetLastWriteTimeUtc( rootDir );

            foreach (string filename in source.GetRelativePathFiles(relativePath) /* PWLib.Platform.Windows.Directory.GetFiles( rootDir ) */)
            {
                try
                {
                    VolumeSnapshotFile fileEntry = VolumeSnapshotFile.BuildFromSource(mSnapshot, source, filename);
                    mFiles.Add(fileEntry);
                }
                catch (System.Exception e)
                {
                    FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromFileSystem failed on file '" + filename + "'", e);
                }
            }

            foreach (string subDir in source.GetRelativePathDirectories(relativePath))
            {
                try
                {
                    if (!IsIgnoredDirectoryName(PWLib.Platform.Windows.Path.GetLeafName(subDir)))
                    {
                        VolumeSnapshotDirectory subDirEntry = new VolumeSnapshotDirectory(mSnapshot, source, subDir);
                        mDirectories.Add(subDirEntry);
                    }
                }
                catch (System.Exception e)
                {
                    FileSync.__LogError(this, "VolumeSnapshotDirectory.BuildFromFileSystem failed on directory '" + subDir + "'", e);
                }
            }
        }
 public void OnDirectoryTheSame( VolumeSnapshotDirectory oldDirectory, VolumeSnapshotDirectory newDirectory )
 {
     mDirectoriesTheSame++;
     if ( mInvokeCallbacks )
     {
         if ( DirectoryTheSame != null )
             DirectoryTheSame( oldDirectory, newDirectory );
     }
 }
 void mComparator_DirectoryTheSame(VolumeSnapshotDirectory oldDirectory, VolumeSnapshotDirectory newDirectory)
 {
     newDirectory.Revision = oldDirectory.Revision;
 }
 void mComparator_DirectoryCreated(VolumeSnapshotDirectory oldDir, VolumeSnapshotDirectory newDir)
 {
     newDir.Revision = newDir.Snapshot.Revision;
     CopyAll(newDir);
 }
Exemplo n.º 19
0
        public static VolumeSnapshotDirectory BuildFromXml(VolumeSnapshot snapshot, XmlNode parentNode)
        {
            VolumeSnapshotDirectory dirEntry = new VolumeSnapshotDirectory(snapshot, parentNode);

            return(dirEntry);
        }
        private bool ProcessDirectory(VolumeSnapshotDirectory oldDb, VolumeSnapshotDirectory newDb)
        {
            // check for new/changed files
            foreach (VolumeSnapshotFile newFile in newDb.Files)
            {
                // see if the file exists in the rhs snapshot and if it has changed
                VolumeSnapshotFile oldFile = oldDb.FindFile(newFile.FileName);
                if (oldFile == null)
                {
                    // File has been created
                    mStats.OnFileCreated(newFile);
                }
                else
                {
                    // File exists in both snapshots, check last modified date
                    if (oldFile.LastModified.Ticks != newFile.LastModified.Ticks)
                    {                     // file has been modified
                        mStats.OnFileChanged(oldFile, newFile);
                    }
                    else
                    {                     // file the same
                        mStats.OnFileTheSame(oldFile, newFile);
                    }
                }

                if (!mOperation.CanContinue)
                {
                    return(mStats.IsModified);
                }
            }

            // check for deleted files
            foreach (VolumeSnapshotFile oldFile in oldDb.Files)
            {
                VolumeSnapshotFile newFile = newDb.FindFile(oldFile.FileName);
                if (newFile == null)
                {
                    mStats.OnFileRemoved(oldFile);
                }

                if (!mOperation.CanContinue)
                {
                    return(mStats.IsModified);
                }
            }

            // check for deleted directories
            foreach (VolumeSnapshotDirectory oldDir in oldDb.Directories)
            {
                VolumeSnapshotDirectory newDir = newDb.FindDirectory(oldDir.Name);
                if (newDir == null)
                {
                    mStats.OnDirectoryRemoved(oldDir);
                }

                if (!mOperation.CanContinue)
                {
                    return(mStats.IsModified);
                }
            }

            // check for new directories
            foreach (VolumeSnapshotDirectory newDir in newDb.Directories)
            {
                VolumeSnapshotDirectory oldDir = oldDb.FindDirectory(newDir.Name);
                if (oldDir == null)
                {
                    // Directory has been created
                    mStats.OnDirectoryCreated(newDir);
                }
                else
                {
                    mStats.OnDirectoryTheSame(oldDir, newDir);

                    ProcessDirectory(oldDir, newDir);
                }

                if (!mOperation.CanContinue)
                {
                    return(mStats.IsModified);
                }
            }

            return(mStats.IsModified);
        }
Exemplo n.º 21
0
 private VolumeSnapshot(VolumeSource source)
 {
     mRevision  = VolumeSnapshotRevision.CreateNew();
     mRoot      = VolumeSnapshotDirectory.BuildFromSource(this, source, "");
     mFileCount = mRoot.CountAllFiles(ref mTotalFileSize);
 }
 void mComparator_DirectoryTheSame( VolumeSnapshotDirectory oldDirectory, VolumeSnapshotDirectory newDirectory )
 {
     newDirectory.Revision = oldDirectory.Revision;
 }
        private bool CopyAll( VolumeSnapshotDirectory directory )
        {
            directory.Revision = directory.Snapshot.Revision;
            mArchive.CreateDirectory( directory.Snapshot.Revision, directory.RelativePath );

            if ( !mOperation.CanContinue )
                return false;

            foreach ( VolumeSnapshotFile fileEntry in directory.Files )
            {
                CopyFileToBackup( fileEntry );

                if ( !mOperation.CanContinue )
                    return false;
            }

            foreach ( VolumeSnapshotDirectory dirEntry in directory.Directories )
            {
                if ( !CopyAll( dirEntry ) || !mOperation.CanContinue )
                    return false;
            }

            return true;
        }
 public static VolumeSnapshotDirectory BuildFromXml( VolumeSnapshot snapshot, XmlNode parentNode )
 {
     VolumeSnapshotDirectory dirEntry = new VolumeSnapshotDirectory( snapshot, parentNode );
     return dirEntry;
 }
 void mComparator_DirectoryCreated( VolumeSnapshotDirectory oldDir, VolumeSnapshotDirectory newDir )
 {
     newDir.Revision = newDir.Snapshot.Revision;
     CopyAll( newDir );
 }
 public void OnDirectoryCreated( VolumeSnapshotDirectory newDirectory )
 {
     mDirectoriesCreated++;
     mIsModified = true;
     ulong numNewFilesInDir = newDirectory.CountAllFiles( ref mTotalFileSize );
     mFileCount += numNewFilesInDir;
     mFilesCreated += numNewFilesInDir;
     if ( mInvokeCallbacks )
     {
         if ( DirectoryCreated != null )
             DirectoryCreated( null, newDirectory );
     }
 }
 public void OnDirectoryRemoved( VolumeSnapshotDirectory oldDirectory )
 {
     mDirectoriesRemoved++;
     mIsModified = true;
 }
 public void OnDirectoryRemoved(VolumeSnapshotDirectory oldDirectory)
 {
     mDirectoriesRemoved++;
     mIsModified = true;
 }
        private VolumeSnapshotDirectory( VolumeSnapshot snapshot, VolumeSource source, string relativePath )
        {
            mSnapshot = snapshot;
            mRelativePath = relativePath;
            mName = mRelativePath.Length <= 1 ? "" : PWLib.Platform.Windows.Path.GetLeafName( relativePath );
            mLastModified = source.GetLastWriteTimeUtc( relativePath );// PWLib.Platform.Windows.Directory.GetLastWriteTimeUtc( rootDir );

            foreach ( string filename in source.GetRelativePathFiles( relativePath ) /* PWLib.Platform.Windows.Directory.GetFiles( rootDir ) */ )
            {
                try
                {
                    VolumeSnapshotFile fileEntry = VolumeSnapshotFile.BuildFromSource( mSnapshot, source, filename );
                    mFiles.Add( fileEntry );
                }
                catch ( System.Exception e )
                {
                    FileSync.__LogError( this, "VolumeSnapshotDirectory.BuildFromFileSystem failed on file '" + filename + "'", e );
                }
            }

            foreach ( string subDir in source.GetRelativePathDirectories( relativePath ) )
            {
                try
                {
                    if ( !IsIgnoredDirectoryName( PWLib.Platform.Windows.Path.GetLeafName( subDir ) ) )
                    {
                        VolumeSnapshotDirectory subDirEntry = new VolumeSnapshotDirectory( mSnapshot, source, subDir );
                        mDirectories.Add( subDirEntry );
                    }
                }
                catch ( System.Exception e )
                {
                    FileSync.__LogError( this, "VolumeSnapshotDirectory.BuildFromFileSystem failed on directory '" + subDir + "'", e );
                }
            }
        }
Exemplo n.º 30
0
        ulong mTotalStoredInThisRevision = 0; // Total unique file size stored in this revision's directory

        #endregion Fields

        #region Constructors

        private VolumeSnapshot( VolumeSource source )
        {
            mRevision = VolumeSnapshotRevision.CreateNew();
            mRoot = VolumeSnapshotDirectory.BuildFromSource( this, source, "" );
            mFileCount = mRoot.CountAllFiles( ref mTotalFileSize );
        }
        void TurnSnapshotIntoBaselinePrivate( VolumeSnapshotDirectory parentDir, ref List<VolumeSnapshotRevision> revisionsThatCanBeRemoved )
        {
            VolumeSnapshotRevision currentRevision = parentDir.Snapshot.Revision;
            foreach ( VolumeSnapshotFile file in parentDir.Files )
            {
                if ( file.Revision.Value < currentRevision.Value )
                {
                    revisionsThatCanBeRemoved.Add( file.Revision );

                    // file is older than current snapshot, copy it into the current snapshot
                    // Use Move for speed - the file will be deleted in the next step anyway and
                    // will no longer be needed
                    mArchive.MoveFileFromRevision( file.Revision, currentRevision, file.RelativePath );

                    // update revision id in .xml file
                    file.Revision = currentRevision;
                }
            }

            foreach ( VolumeSnapshotDirectory dir in parentDir.Directories )
            {
                if ( dir.Revision.Value < currentRevision.Value )
                    dir.Revision = currentRevision;
                TurnSnapshotIntoBaselinePrivate( dir, ref revisionsThatCanBeRemoved );
            }
        }
        void UpdateSnapshotToReflectBaselineRevisionPrivate( VolumeSnapshotDirectory parentDir, VolumeSnapshotRevision newRevision )
        {
            foreach ( VolumeSnapshotFile file in parentDir.Files )
            {
                if ( file.Revision.Value < newRevision.Value )
                    file.Revision = newRevision;
            }

            foreach ( VolumeSnapshotDirectory dir in parentDir.Directories )
            {
                if ( dir.Revision.Value < newRevision.Value )
                    dir.Revision = newRevision;
                UpdateSnapshotToReflectBaselineRevisionPrivate( dir, newRevision );
            }
        }
        private bool ProcessDirectory( VolumeSnapshotDirectory oldDb, VolumeSnapshotDirectory newDb )
        {
            // check for new/changed files
            foreach ( VolumeSnapshotFile newFile in newDb.Files )
            {
                // see if the file exists in the rhs snapshot and if it has changed
                VolumeSnapshotFile oldFile = oldDb.FindFile( newFile.FileName );
                if ( oldFile == null )
                {
                    // File has been created
                    mStats.OnFileCreated( newFile );
                }
                else
                {
                    // File exists in both snapshots, check last modified date
                    if ( oldFile.LastModified.Ticks != newFile.LastModified.Ticks )
                    { // file has been modified
                        mStats.OnFileChanged( oldFile, newFile );
                    }
                    else
                    { // file the same
                        mStats.OnFileTheSame( oldFile, newFile );
                    }
                }

                if ( !mOperation.CanContinue )
                    return mStats.IsModified;
            }

            // check for deleted files
            foreach ( VolumeSnapshotFile oldFile in oldDb.Files )
            {
                VolumeSnapshotFile newFile = newDb.FindFile( oldFile.FileName );
                if ( newFile == null )
                {
                    mStats.OnFileRemoved( oldFile );
                }

                if ( !mOperation.CanContinue )
                    return mStats.IsModified;
            }

            // check for deleted directories
            foreach ( VolumeSnapshotDirectory oldDir in oldDb.Directories )
            {
                VolumeSnapshotDirectory newDir = newDb.FindDirectory( oldDir.Name );
                if ( newDir == null )
                {
                    mStats.OnDirectoryRemoved( oldDir );
                }

                if ( !mOperation.CanContinue )
                    return mStats.IsModified;
            }

            // check for new directories
            foreach ( VolumeSnapshotDirectory newDir in newDb.Directories )
            {
                VolumeSnapshotDirectory oldDir = oldDb.FindDirectory( newDir.Name );
                if ( oldDir == null )
                {
                    // Directory has been created
                    mStats.OnDirectoryCreated( newDir );
                }
                else
                {
                    mStats.OnDirectoryTheSame( oldDir, newDir );

                    ProcessDirectory( oldDir, newDir );
                }

                if ( !mOperation.CanContinue )
                    return mStats.IsModified;
            }

            return mStats.IsModified;
        }
        private void ProcessDirectoryRestore( VolumeSnapshotDirectory sourceDir, BaseArchive archive, int relativePathStartIndex, string targetDir )
        {
            if ( !mOperation.CanContinue )
                return;

            PWLib.Platform.Windows.Directory.CreateDirectory( targetDir );

            foreach ( VolumeSnapshotFile fileEntry in sourceDir.Files )
            {
                try
                {
                    string outDir = targetDir + fileEntry.RelativePath.Substring( relativePathStartIndex );
                    archive.RestoreFile( fileEntry.Revision, fileEntry.RelativePath, outDir, new ArchiveFileDelegate( Restore_ArchiveStoreFile ), fileEntry );

                    ulong runningSize = mFilesTotalSizeRunning + fileEntry.FileSize;
                    if ( runningSize > mFilesTotalSize )
                        runningSize = mFilesTotalSize;
                    if ( Progress != null )
                        Progress( mFileRunningCount + 1, mFileTotalCount, runningSize, mFilesTotalSize );
                }
                catch ( System.Exception e )
                {
                    if ( Error != null )
                        Error( "Restore file failed '" + fileEntry.RelativePath + "'", e );
                }

                if ( !mOperation.CanContinue )
                    return;

                mFileRunningCount++;
                mFilesTotalSizeRunning += fileEntry.FileSize;
            }

            foreach ( VolumeSnapshotDirectory directoryEntry in sourceDir.Directories )
            {
                ProcessDirectoryRestore( directoryEntry, archive, relativePathStartIndex, targetDir );
                if ( !mOperation.CanContinue )
                    return;
            }
        }