//***************************************************************************** // // Class: BackupFile // Author: Kenny Kerr // Date created: 6 May 2003 // //***************************************************************************** using System; using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; namespace Kerr.Samples { /// /// The BackupFile class provides a simple interface for backing up and /// restoring files. It uses the Windows Backup API functions. /// unsafe public class BackupFile : IDisposable { #region Constructors /// /// Creates a new BackupFile object to backup or restore the specified file. /// /// /// The name of the file or directory. /// /// /// Indicates whether the file is being backed up or restored. Specify true /// to open the file for backup, or false to prepare to restore the file. /// public BackupFile(string path, bool backup) { uint desiredAccess = 0; uint creationDisposition = 0; if (backup) { desiredAccess = GENERIC_READ; creationDisposition = OPEN_EXISTING; } else { desiredAccess = GENERIC_WRITE | WRITE_OWNER | WRITE_DAC; creationDisposition = CREATE_ALWAYS; } m_handle = CreateFile(path, desiredAccess, 0, IntPtr.Zero, creationDisposition, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); if (INVALID_HANDLE_VALUE == m_handle) { throw new Win32Exception(); } } #endregion #region Methods /// /// Releases the file handle. /// public void Dispose() { if (IntPtr.Zero != m_handle) { if (!CloseHandle(m_handle)) { throw new Win32Exception(); } } } /// /// Saves the file to the stream. /// public void Backup(Stream destination) { byte[] buffer = new byte[1024]; fixed (byte* pBuffer = &buffer[0]) { uint bytesRead = 0; IntPtr context = IntPtr.Zero; do { if (!BackupRead(m_handle, pBuffer, (uint) buffer.Length, out bytesRead, false, true, ref context)) { throw new Win32Exception(); } destination.Write(buffer, 0, (int) bytesRead); } while (0 != bytesRead); if (!BackupRead(IntPtr.Zero, null, 0, out bytesRead, true, true, ref context)) { throw new Win32Exception(); } } destination.Flush(); } /// /// Restores the file from the stream. /// public void Restore(Stream source) { byte[] buffer = new byte[1024]; fixed (byte* pBuffer = &buffer[0]) { uint bytesRead = 0; uint bytesWritten = 0; IntPtr context = IntPtr.Zero; do { bytesRead = (uint) source.Read(buffer, 0, buffer.Length); if (!BackupWrite(m_handle, pBuffer, bytesRead, out bytesWritten, false, true, ref context) || bytesRead != bytesWritten) { throw new Win32Exception(); } } while (0 != bytesRead); if (!BackupWrite(IntPtr.Zero, null, 0, out bytesWritten, true, true, ref context)) { throw new Win32Exception(); } } } #endregion #region Fields private IntPtr m_handle; #endregion #region External private const uint GENERIC_READ = 0x80000000; private const uint GENERIC_WRITE = 0x40000000; private const uint OPEN_EXISTING = 3; private const uint CREATE_ALWAYS = 2; private const uint WRITE_DAC = 0x00040000; private const uint WRITE_OWNER = 0x00080000; private const uint ACCESS_SYSTEM_SECURITY = 0x01000000; private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern IntPtr CreateFile(string path, uint desiredAccess, uint shareMode, IntPtr securityAttributes, uint creationDisposition, uint flagsAndAttributes, IntPtr templateHandle); [DllImport("kernel32.dll", SetLastError=true)] private static extern bool CloseHandle(IntPtr handle); [DllImport("kernel32.dll", SetLastError=true)] private static extern bool BackupRead(IntPtr handle, byte* buffer, uint bytesToRead, out uint bytesRead, bool abort, bool processSecurity, ref IntPtr context); [DllImport("kernel32.dll", SetLastError=true)] private static extern bool BackupWrite(IntPtr handle, byte* buffer, uint bytesToWrite, out uint bytesWritten, bool abort, bool processSecurity, ref IntPtr context); #endregion } }