/*
* Copyright (C) 2006-2007 Eskil Bylund
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using DCSharp.Hashing;
using DCSharp.Logging;
using DCSharp.Security.Cryptography;
namespace DCSharp.Backend.Managers{
public class HashEventArgs : EventArgs
{
public HashEventArgs(FileInfo fileInfo, HashTree hashTree)
{
this.fileInfo = fileInfo;
this.hashTree = hashTree;
}
public FileInfo FileInfo
{
get { return fileInfo; }
}
private FileInfo fileInfo;
public HashTree HashTree
{
get { return hashTree; }
}
private HashTree hashTree;
}
/// <summary>
/// A class that handles the hashing of files.
/// </summary>
public class HashManager
{
private static Logger log = LogManager.GetLogger("HashManager");
public event EventHandler<HashEventArgs> FileHashed;
private Dictionary<string, long> files;
private string currentFile;
private Thread thread;
private Hasher hasher;
private ManualResetEvent abortHashingEvent;
public HashManager()
{
files = new Dictionary<string, long>();
hasher = Hasher.Create(Tiger.Create());
abortHashingEvent = new ManualResetEvent(false);
}
#region Properties
/// <summary>
/// Gets the number of bytes that remains until all files have been hashed.
/// </summary>
public long BytesRemaining
{
get
{
return bytesRemaining + hasher.BytesRemaining;
}
}
private long bytesRemaining;
#endregion
#region Methods
/// <summary>
/// Adds a file to the hash queue.
/// </summary>
/// <param name="fileInfo">The file to be hashed.</param>
public void Hash(FileInfo fileInfo)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
lock (files)
{
if (!files.ContainsKey(fileInfo.FullName))
{
files.Add(fileInfo.FullName, fileInfo.Length);
bytesRemaining += fileInfo.Length;
Start();
}
}
}
/// <summary>
/// Removes a file from the hash queue.
/// </summary>
/// <param name="fileInfo">The file to remove.</param>
public void AbortHash(FileInfo fileInfo)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
AbortHash(fileInfo.FullName);
}
/// <summary>
/// Removes a file from the hash queue.
/// </summary>
/// <param name="filename">The file to remove.</param>
public void AbortHash(string filename)
{
if (filename == null)
{
throw new ArgumentNullException("filename");
}
lock (files)
{
if (files.ContainsKey(filename))
{
bytesRemaining -= files[filename];
files.Remove(filename);
}
if (currentFile == filename)
{
abortHashingEvent.Set();
}
}
}
/// <summary>
/// Starts the hashing thread.
/// </summary>
protected void Start()
{
lock (files)
{
if (thread == null)
{
thread = new Thread(HashStart);
thread.Name = "Hashing Thread";
thread.IsBackground = true;
thread.Start();
}
}
}
/// <summary>
/// Emits the FileHashed event.
/// </summary>
/// <param name="fileInfo">The file that's been hashed.</param>
/// <param name="hashTree">The resulting hash tree.</param>
protected virtual void OnFileHashed(FileInfo fileInfo, HashTree hashTree)
{
if (FileHashed != null)
{
FileHashed(this, new HashEventArgs(fileInfo, hashTree));
}
}
private void HashStart()
{
while (true)
{
currentFile = null;
lock (files)
{
IEnumerator<KeyValuePair<string, long>> enumerator = files.GetEnumerator();
if (enumerator.MoveNext())
{
currentFile = enumerator.Current.Key;
bytesRemaining -= enumerator.Current.Value;
files.Remove(currentFile);
}
else
{
thread = null;
break;
}
}
try
{
FileInfo fileInfo = new FileInfo(currentFile);
log.Info("Hashing " + fileInfo.FullName);
HashTree hashTree = hasher.Hash(fileInfo,
abortHashingEvent);
// The hashing was not aborted
if (!abortHashingEvent.WaitOne(0, false))
{
OnFileHashed(fileInfo, hashTree);
}
else
{
abortHashingEvent.Reset();
}
}
catch (FileNotFoundException)
{
}
catch (Exception e)
{
log.Error("Hashing failed", e);
}
}
}
#endregion
}
}
|