/*==
== Copyright : BlueCurve (c)
== Licence : Gnu/GPL v2.x
== Author : Teddy Albina
== Email : bluecurveteam@gmail.com
== Web site : http://www.codeplex.com/BlueCurve
*/
using System;
using System.IO;
using System.Text;
using System.Transactions;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
namespace BlueCurve.Search.Common.IO
{
///
/// Fournit des méthodes de gestions du système de fichier
///
public class CommonStream
{
#region Import native methods
///
/// Méthode native vérifiant si un répertoire est vide
///
/// Chemin du répertoire à tester
/// bool
[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
private extern static bool PathIsDirectoryEmpty(string pszPath);
#region 'Kernel transaction manager api management'
///
/// Represente un handle de transaction
///
public sealed class SafeTransactionHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTransactionHandle()
: base(true)
{
}
public SafeTransactionHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
SetHandle(preexistingHandle);
}
public enum FileAccess
{
GENERIC_READ = unchecked((int)0x80000000),
GENERIC_WRITE = 0x40000000
}
[Flags]
public enum FileShare
{
FILE_SHARE_NONE = 0x00,
FILE_SHARE_READ = 0x01,
FILE_SHARE_WRITE = 0x02,
FILE_SHARE_DELETE = 0x04
}
public enum FileMode
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
override protected bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
///
/// Importation de la fonction native CreateFileTransacted() permettant
/// de créer une transaction ntfs
///
/// SafeFileHandle
[DllImport("Kernel32.Dll", EntryPoint = "CreateFileTransacted", CharSet = CharSet.Unicode, SetLastError = true)]
protected static extern SafeFileHandle CreateFileTransacted(
[In] String lpFileName,
[In] SafeTransactionHandle.FileAccess dwDesiredAccess,
[In] SafeTransactionHandle.FileShare dwShareMode,
[In] IntPtr lpSecurityAttributes,
[In] SafeTransactionHandle.FileMode dwCreationDisposition,
[In] int dwFlagsAndAttributes,
[In] IntPtr hTemplateFile,
[In] SafeTransactionHandle txHandle,
[In] IntPtr miniVersion,
[In] IntPtr extendedOpenInformation
);
///
/// Importation de l'interface KTM
///
[ComImport]
[Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
protected interface IKernelTransaction
{
void GetHandle(out SafeTransactionHandle ktmHandle);
}
#endregion
#endregion
///
/// Copie un stream dans un autre
/// de façon asynchrone
/// http://msdn.microsoft.com/fr-fr/magazine/cc337900.aspx
///
/// Stream source
/// Stream destination
/// Action()
public static void CopyStreamToStream(FileStream source, FileStream destination,
Action completed)
{
byte[] buffer = new byte[0x1024];
System.ComponentModel.AsyncOperation asyncOp = System.ComponentModel.AsyncOperationManager.CreateOperation(null);
Action done = e =>
{
if (completed != null) asyncOp.Post(delegate
{
completed(source, destination, e);
}, null);
};
AsyncCallback rc = null;
rc = readResult =>
{
try
{
int read = source.EndRead(readResult);
if (read > 0)
{
destination.BeginWrite(buffer, 0, read, writeResult =>
{
try
{
destination.EndWrite(writeResult);
source.BeginRead(
buffer, 0, buffer.Length, rc, null);
}
catch (Exception exc) { done(exc); }
}, null);
}
else done(null);
}
catch (Exception exc) { done(exc); }
};
source.BeginRead(buffer, 0, buffer.Length, rc, null);
}
///
/// Vérifie qu'un répertoire est vide
///
/// Chemin de fichier du répertoire
/// bool
public static bool DirectoryIsEmpty(string path)
{
return PathIsDirectoryEmpty(path);
}
#region Transactional methods
///
/// Ecrit un fichier de façon transactionnel
///
/// Données à écrire
/// Chemin du fichier dans lequel écrire les données
/// Statut de l'opération
public static bool WriteFileTransacted(object data, string path)
{
if (data == null)
return false;
SafeTransactionHandle txHandle = null;
SafeFileHandle fileHandle = null;
bool response = true;
try
{
IKernelTransaction kernelTx = (IKernelTransaction)TransactionInterop.GetDtcTransaction(System.Transactions.Transaction.Current);
kernelTx.GetHandle(out txHandle);
fileHandle
= CreateFileTransacted(
path
, SafeTransactionHandle.FileAccess.GENERIC_WRITE
, SafeTransactionHandle.FileShare.FILE_SHARE_NONE
, IntPtr.Zero
, SafeTransactionHandle.FileMode.CREATE_ALWAYS
, 0
, IntPtr.Zero
, txHandle
, IntPtr.Zero
, IntPtr.Zero);
if (fileHandle.IsInvalid)
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
using (FileStream stream = new FileStream(fileHandle, FileAccess.Write, 1024, false))
{
BinaryFormatter writer = new BinaryFormatter();
writer.Serialize(stream, data);
stream.Close();
}
}
catch
{
System.Transactions.Transaction.Current.Rollback();
response = false;
}
finally
{
if (fileHandle != null && !fileHandle.IsInvalid)
{
fileHandle.Close();
fileHandle.Dispose();
}
if (txHandle != null && !txHandle.IsInvalid)
{
txHandle.Close();
txHandle.Dispose();
}
}
return response;
}
///
/// Lit un fichier de façon transactionnel
///
/// Chemin du fichier à lire
/// Données lu
public object ReadFileTransacted(string path)
{
if (!File.Exists(path))
return null;
SafeTransactionHandle txHandle = null;
SafeFileHandle fileHandle = null;
object raw = null;
try
{
IKernelTransaction kernelTx = (IKernelTransaction)TransactionInterop.GetDtcTransaction(System.Transactions.Transaction.Current);
kernelTx.GetHandle(out txHandle);
fileHandle
= CreateFileTransacted(
path
, SafeTransactionHandle.FileAccess.GENERIC_READ
, SafeTransactionHandle.FileShare.FILE_SHARE_READ
, IntPtr.Zero
, SafeTransactionHandle.FileMode.OPEN_ALWAYS
, 0
, IntPtr.Zero
, txHandle
, IntPtr.Zero
, IntPtr.Zero);
if (fileHandle.IsInvalid)
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
using (FileStream stream = new FileStream(fileHandle, FileAccess.Read, 1024, false))
{
BinaryFormatter reader = new BinaryFormatter();
raw = reader.Deserialize(stream);
}
}
catch
{
raw = null;
}
finally
{
if (fileHandle != null && !fileHandle.IsInvalid)
{
fileHandle.Close();
fileHandle.Dispose();
}
if (txHandle != null && !txHandle.IsInvalid)
{
txHandle.Close();
txHandle.Dispose();
}
}
return raw;
}
#endregion
}
}