예제 #1
0
        /// <summary>
        /// Read data direct from drive to file
        /// </summary>
        /// <param name="driveLetter"></param>
        /// <param name="fileName"></param>
        /// <param name="eCompType"></param>
        /// <returns></returns>
        public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool bUseMBR, long start, long length)
        {
            IsCancelling = false;

            var dtStart = DateTime.Now;

            //
            // Map to physical drive
            //
            var physicalDrive = _diskAccess.GetPhysicalPathForLogicalPath(driveLetter);

            if (string.IsNullOrEmpty(physicalDrive))
            {
                LogMsg(@"Error: Couldn't map partition to physical drive");
                _diskAccess.UnlockDrive();
                return(false);
            }

            //
            // Lock logical drive
            //
            var success = _diskAccess.LockDrive(driveLetter);

            if (!success)
            {
                LogMsg(@"Failed to lock drive");
                return(false);
            }

            //
            // Get drive size
            //
            var driveSize = _diskAccess.GetDriveSize(physicalDrive);

            if (driveSize <= 0)
            {
                LogMsg(@"Failed to get device size");
                _diskAccess.UnlockDrive();
                return(false);
            }

            var readSize = driveSize;

            //
            // Open the physical drive
            //
            var physicalHandle = _diskAccess.Open(physicalDrive);

            if (physicalHandle == null)
            {
                LogMsg(@"Failed to open physical drive");
                _diskAccess.UnlockDrive();
                return(false);
            }

            //
            // Start doing the read
            //

            var buffer = new byte[Globals.MaxBufferSize];
            var offset = 0L;

            using (var basefs = (Stream) new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                Stream fs;

                switch (eCompType)
                {
                case EnumCompressionType.Zip:
                {
                    var zfs = new ZipOutputStream(basefs);

                    // Default to middle of the range compression
                    zfs.SetLevel(Globals.CompressionLevel);

                    var fi        = new FileInfo(fileName);
                    var entryName = fi.Name;
                    entryName = entryName.ToLower().Replace(".zip", "");
                    entryName = ZipEntry.CleanName(entryName);
                    var zipEntry = new ZipEntry(entryName)
                    {
                        DateTime = fi.LastWriteTime
                    };
                    zfs.IsStreamOwner = true;

                    // Todo: Consider whether size needs setting for older utils ?

                    zfs.PutNextEntry(zipEntry);

                    fs = zfs;
                }
                break;

                case EnumCompressionType.Gzip:
                {
                    var gzos = new GZipOutputStream(basefs);
                    gzos.SetLevel(Globals.CompressionLevel);
                    gzos.IsStreamOwner = true;

                    fs = gzos;
                }
                break;

                case EnumCompressionType.Targzip:
                {
                    var gzos = new GZipOutputStream(basefs);
                    gzos.SetLevel(Globals.CompressionLevel);
                    gzos.IsStreamOwner = true;

                    var tos = new TarOutputStream(gzos);

                    fs = tos;
                }
                break;

                default:

                    // No compression - direct to file stream
                    fs = basefs;
                    break;
                }


                while (offset < readSize && !IsCancelling)
                {
                    // NOTE: If we provide a buffer that extends past the end of the physical device ReadFile() doesn't
                    //       seem to do a partial read. Deal with this by reading the remaining bytes at the end of the
                    //       drive if necessary

                    var readMaxLength =
                        (int)
                        ((((ulong)readSize - (ulong)offset) < (ulong)buffer.Length)
                                 ? ((ulong)readSize - (ulong)offset)
                                 : (ulong)buffer.Length);

                    int readBytes;
                    if (_diskAccess.Read(buffer, readMaxLength, out readBytes) < 0)
                    {
                        LogMsg(@"Error reading data from drive: " +
                               Marshal.GetHRForLastWin32Error());
                        goto readfail1;
                    }

                    if (readBytes == 0)
                    {
                        LogMsg(@"Error reading data from drive - past EOF?");
                        goto readfail1;
                    }

                    // Check MBR
                    if (bUseMBR && offset == 0)
                    {
                        var truncatedSize = ParseMBRForSize(buffer);

                        if (truncatedSize > driveSize)
                        {
                            LogMsg("Problem with filesystem. It reports it is larger than the disk!");
                            goto readfail1;
                        }

                        if (truncatedSize == 0)
                        {
                            LogMsg("No valid partitions on drive");
                            goto readfail1;
                        }

                        readSize = truncatedSize;
                    }

                    if (offset == 0)
                    {
                        switch (eCompType)
                        {
                        case EnumCompressionType.Targzip:
                            var fi        = new FileInfo(fileName);
                            var entryName = fi.Name;
                            entryName = entryName.ToLower().Replace(".tar.gz", "");
                            entryName = entryName.ToLower().Replace(".tgz", "");

                            var tarEntry = TarEntry.CreateTarEntry(entryName);
                            tarEntry.Size    = readSize;
                            tarEntry.ModTime = DateTime.SpecifyKind(fi.LastWriteTime, DateTimeKind.Utc);

                            ((TarOutputStream)fs).PutNextEntry(tarEntry);

                            break;
                        }
                    }

                    fs.Write(buffer, 0, readBytes);

                    offset += (uint)readBytes;

                    var percentDone = (int)(100 * offset / readSize);
                    var tsElapsed   = DateTime.Now.Subtract(dtStart);
                    var bytesPerSec = offset / tsElapsed.TotalSeconds;

                    Progress(percentDone);
                    LogMsg(@"Read " + percentDone + @"%, " + (offset / (1024 * 1024)) + @" MB / " +
                           (readSize / (1024 * 1024) + " MB (Physical: " + (driveSize / (1024 * 1024)) + " MB), " +
                            string.Format("{0:F}", (bytesPerSec / (1024 * 1024))) + @" MB/sec, Elapsed time: " +
                            tsElapsed.ToString(@"dd\.hh\:mm\:ss")));
                }

                // Todo: Do we need this?
                if (fs is ZipOutputStream)
                {
                    ((ZipOutputStream)fs).CloseEntry();
                    ((ZipOutputStream)fs).Close();
                }
                if (fs is TarOutputStream)
                {
                    ((TarOutputStream)fs).CloseEntry();
                    ((TarOutputStream)fs).Close();
                }
                if (fs is GZipOutputStream)
                {
                    //                    ((GZipOutputStream) fs).Finish();
                    ((GZipOutputStream)fs).Close();
                }
            }

readfail1:

            _diskAccess.Close();

            _diskAccess.UnlockDrive();

            var tstotalTime = DateTime.Now.Subtract(dtStart);

            if (IsCancelling)
            {
                LogMsg("Cancelled");
            }
            else
            {
                LogMsg("All Done - Read " + offset + " bytes. Elapsed time " + tstotalTime.ToString(@"dd\.hh\:mm\:ss"));
            }
            Progress(0);
            return(true);
        }
예제 #2
0
        /// <summary>
        /// Read data direct from drive to file
        /// </summary>
        /// <param name="driveLetter"></param>
        /// <param name="fileName"></param>
        /// <param name="eCompType"></param>
        /// <returns></returns>
        public bool ReadDrive(string driveLetter, string fileName, EnumCompressionType eCompType, bool bUseMBR)
        {
            IsCancelling = false;

            var dtStart = DateTime.Now;

            //
            // Map to physical drive
            //
            var physicalDrive = _diskAccess.GetPhysicalPathForLogicalPath(driveLetter);

            if (string.IsNullOrEmpty(physicalDrive))
            {
                LogMsg(Resources.Disk_WriteDrive_Error__Couldn_t_map_partition_to_physical_drive);
                _diskAccess.UnlockDrive();
                return(false);
            }

            //
            // Lock logical drive
            //
            var success = _diskAccess.LockDrive(driveLetter);

            if (!success)
            {
                LogMsg(Resources.Disk_WriteDrive_Failed_to_lock_drive);
                return(false);
            }

            //
            // Get drive size
            //
            var driveSize = _diskAccess.GetDriveSize(physicalDrive);

            if (driveSize <= 0)
            {
                LogMsg(Resources.Disk_WriteDrive_Failed_to_get_device_size);
                _diskAccess.UnlockDrive();
                return(false);
            }

            var readSize = driveSize;

            //
            // Open the physical drive
            //
            var physicalHandle = _diskAccess.Open(physicalDrive);

            if (physicalHandle == null)
            {
                LogMsg(Resources.Disk_WriteDrive_Failed_to_open_physical_drive);
                _diskAccess.UnlockDrive();
                return(false);
            }

            //
            // Start doing the read
            //

            var buffer = new byte[Globals.MaxBufferSize];
            var offset = 0L;

            using (var basefs = (Stream) new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                Stream fs;

                switch (eCompType)
                {
                case EnumCompressionType.Zip:
                    var zfs = new ZipOutputStream(basefs);

                    // Default to middle of the range compression
                    zfs.SetLevel(Globals.CompressionLevel);

                    var fi        = new FileInfo(fileName);
                    var entryName = fi.Name;
                    entryName = entryName.ToLower().Replace(".zip", "");
                    entryName = ZipEntry.CleanName(entryName);
                    var zipEntry = new ZipEntry(entryName)
                    {
                        DateTime = fi.LastWriteTime
                    };
                    zfs.IsStreamOwner = true;

                    // Todo: Consider whether size needs setting for older utils ?

                    zfs.PutNextEntry(zipEntry);

                    fs = zfs;

                    break;

                case EnumCompressionType.Gzip:

                    var gzis = new GZipOutputStream(basefs);
                    gzis.SetLevel(Globals.CompressionLevel);
                    gzis.IsStreamOwner = true;

                    fs = gzis;

                    break;

                case EnumCompressionType.Targzip:

                    var gzos = new GZipOutputStream(basefs);
                    gzos.SetLevel(Globals.CompressionLevel);
                    gzos.IsStreamOwner = true;

                    var tos = new TarOutputStream(gzos);

                    fs = tos;

                    break;

                case EnumCompressionType.XZ:

                    var xzs = new XZOutputStream(basefs);
                    fs = xzs;

                    break;

                default:

                    // No compression - direct to file stream
                    fs = basefs;

                    break;
                }

                while (offset < readSize && !IsCancelling)
                {
                    // NOTE: If we provide a buffer that extends past the end of the physical device ReadFile() doesn't
                    //       seem to do a partial read. Deal with this by reading the remaining bytes at the end of the
                    //       drive if necessary

                    var readMaxLength =
                        (int)
                        ((((ulong)readSize - (ulong)offset) < (ulong)buffer.Length)
                                 ? ((ulong)readSize - (ulong)offset)
                                 : (ulong)buffer.Length);

                    int readBytes;
                    if (_diskAccess.Read(buffer, readMaxLength, out readBytes) < 0)
                    {
                        LogMsg(Resources.Disk_ReadDrive_Error_reading_data_from_drive__ +
                               Marshal.GetHRForLastWin32Error());
                        goto readfail1;
                    }

                    if (readBytes == 0)
                    {
                        LogMsg(Resources.Disk_ReadDrive_Error_reading_data_from_drive___past_EOF_);
                        goto readfail1;
                    }

                    // Check MBR
                    if (bUseMBR && offset == 0)
                    {
                        var truncatedSize = ParseMBRForSize(buffer);

                        if (truncatedSize > driveSize)
                        {
                            LogMsg(Resources.Disk_ReadDrive_Problem_with_filesystem__It_reports_it_is_larger_than_the_disk_);
                            goto readfail1;
                        }

                        if (truncatedSize == 0)
                        {
                            LogMsg(Resources.Disk_ReadDrive_No_valid_partitions_on_drive);
                            goto readfail1;
                        }

                        readSize = truncatedSize;
                    }

                    if (offset == 0)
                    {
                        switch (eCompType)
                        {
                        case EnumCompressionType.Targzip:
                            var fi        = new FileInfo(fileName);
                            var entryName = fi.Name;
                            entryName = entryName.ToLower().Replace(".tar.gz", "");
                            entryName = entryName.ToLower().Replace(".tgz", "");

                            var tarEntry = TarEntry.CreateTarEntry(entryName);
                            tarEntry.Size    = readSize;
                            tarEntry.ModTime = DateTime.SpecifyKind(fi.LastWriteTime, DateTimeKind.Utc);

                            ((TarOutputStream)fs).PutNextEntry(tarEntry);

                            break;
                        }
                    }

                    fs.Write(buffer, 0, readBytes);

                    offset += (uint)readBytes;

                    var percentDone = (int)(100 * offset / readSize);
                    var tsElapsed   = DateTime.Now.Subtract(dtStart);
                    var bytesPerSec = offset / tsElapsed.TotalSeconds;

                    Progress(percentDone);
                    LogMsg(Resources.Disk_ReadDrive_Read + @": " + (offset / Globals.MbModifier) + @" / " +
                           (readSize / Globals.MbModifier) + @" MB " + @"(" + Resources.Disk_ReadDrive_Physical + @": " + (driveSize / Globals.MbModifier) + " MB); " +
                           string.Format("{0:F}", (bytesPerSec / Globals.MbModifier)) + @" MB/s; " + Resources.Disk_Elapsed_time + ": " +
                           tsElapsed.ToString(@"hh\:mm\:ss"));
                }

                if (fs is ZipOutputStream)
                {
                    ((ZipOutputStream)fs).CloseEntry();
                    ((ZipOutputStream)fs).Close();
                }
                else if (fs is TarOutputStream)
                {
                    ((TarOutputStream)fs).CloseEntry();
                    fs.Close();
                }
                else if (fs is GZipOutputStream)
                {
                    fs.Close();
                }
                else if (fs is XZOutputStream)
                {
                    fs.Close();
                }
            }

readfail1:

            _diskAccess.Close();

            _diskAccess.UnlockDrive();

            var tstotalTime = DateTime.Now.Subtract(dtStart);

            if (IsCancelling)
            {
                LogMsg(Resources.Disk_WriteDrive_Cancelled);
            }
            else
            {
                LogMsg(Resources.Disk_ReadDrive_All_Done_Read + @" " + offset + @" " + Resources.Disk_WriteDrive_bytes + @". " + Resources.Disk_Elapsed_time + @": " + tstotalTime.ToString(@"hh\:mm\:ss"));
            }
            Progress(0);
            return(true);
        }