Example #1
0
        //рекурсивынй метод для восстановления и сборки файлов.
        private void CreateFolderWithFiles(string parentPath, DriveDirectory folder)
        {
            foreach (var dir in folder.Directories)
            {
                if (!Directory.Exists(parentPath + GetClearFileName(dir.Name)))
                {
                    Directory.CreateDirectory(parentPath + GetClearFileName(dir.Name));
                }
                CreateFolderWithFiles(parentPath + GetClearFileName(dir.Name) + "\\", dir);
            }

            foreach (var file in folder.Files)
            {
                if (file.Clasters.Count > 0) //не делаем пустые файлы. Нафиг они не нужны.
                {
                    FileStream fs = null;

                    try
                    {
                        fs = new FileStream(parentPath + GetClearFileName(file.Name), FileMode.OpenOrCreate);

                        for (int i = 0; i < file.Clasters.Count - 1; i++)
                        {
                            var Data = Read((file.Clasters[i] - 2) * ClasterSize, (int)ClasterSize);

                            fs.WriteAsync(Data, 0, (int)ClasterSize);
                        }

                        //у последнего кластера мы убираем все нули в конце. Иначе файл будет некорректно восстановлен.
                        var LastClasterData = Read((file.Clasters[file.Clasters.Count - 1] - 2) * ClasterSize, (int)ClasterSize);

                        int countOfZeroBytes = 0;

                        while (LastClasterData[LastClasterData.Length - countOfZeroBytes - 1] == 0)
                        {
                            countOfZeroBytes++;
                        }

                        fs.Write(LastClasterData, 0, (int)ClasterSize - countOfZeroBytes);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message);
                    }
                    finally
                    {
                        if (fs != null)
                        {
                            fs.Close();
                        }
                    }
                }
            }
        }
        private void chooseDriveBtn_Click(object sender, RoutedEventArgs e)
        {
            byte[] Data;

            //освобождаем доступ к флешке.
            if (DiskHandle != null)
            {
                DiskHandle.Close();
            }

            #region maxRecoverySize

            try
            {
                MAX_RECOVERING_FILE_SIZE *= int.Parse(MaxRecoverySizeTB.Text);
            }
            catch
            {
                System.Windows.Forms.MessageBox.Show("Максимальный размер файла указан неверно. Установлено значение по умолчанию: 50 МБ.");
                MAX_RECOVERING_FILE_SIZE = 50 * 1024 * 1024;
            }

            #endregion

            try
            {
                FolderBrowserDialog folderDialog = new FolderBrowserDialog();

                if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    //обновляем букву выбранного диска.
                    tbName.Text = folderDialog.SelectedPath;

                    //приводим имя выбранной флешки к нормальному формату
                    var DiskName = folderDialog.SelectedPath.Split('\\')[0];

                    #region takingHandle

                    //забираем handle для доступа к диску
                    DiskHandle = CreateFile(
                        lpFileName: @"\\.\" + DiskName,
                        dwDesiredAccess: FileAccess.Read,
                        dwShareMode: FileShare.ReadWrite,
                        lpSecurityAttributes: IntPtr.Zero,
                        dwCreationDisposition: FileMode.OpenOrCreate,
                        dwFlagsAndAttributes: FileAttributes.Normal,
                        hTemplateFile: IntPtr.Zero);

                    #endregion

                    //открываем поток на чтение
                    diskStreamToRead = new FileStream(DiskHandle, FileAccess.Read);

                    //читаем загрузочный сектор
                    Data = Read(0, BOOT_SECTOR_SIZE);

                    var FileSystemType = DecimalToASCII(Data, 82, 89);
                    tbFileSystem.Text = FileSystemType;

                    if (!FileSystemType.Contains("FAT32"))
                    {
                        System.Windows.Forms.MessageBox.Show("Программа работает только с системой FAT32");
                        return;
                    }

                    #region GetAndDisplaySpace

                    ulong OutFreeBytesAvaliable     = 0;
                    ulong OutTotalNumberOfBytes     = 0;
                    ulong OutTotalNumberOfFreeBytes = 0;


                    GetDiskFreeSpaceEx(
                        folderDialog.SelectedPath,
                        out OutFreeBytesAvaliable,
                        out OutTotalNumberOfBytes,
                        out OutTotalNumberOfFreeBytes);

                    tbTotal.Text = Math.Round(((double)OutTotalNumberOfBytes / 1024 / 1024 / 1024), 2) + " Гб";
                    tbFree.Text  = Math.Round(((double)OutTotalNumberOfFreeBytes / 1024 / 1024 / 1024), 2) + " Гб";

                    #endregion

                    #region readOptions

                    long SectorSize = HexToDecimal(Data, 11, 12);
                    long NumberOfSectorsInClaster = HexToDecimal(Data, 13, 13);
                    long NumberOfReservedSectors  = HexToDecimal(Data, 14, 15);
                    long NumberOfFatCopies        = HexToDecimal(Data, 16, 16);
                    long FatTableSizeInSectors    = HexToDecimal(Data, 36, 39);
                    long SectorsInFileSystem      = HexToDecimal(Data, 32, 35);

                    #endregion

                    ClasterSize = NumberOfSectorsInClaster * SectorSize;
                    //смещение к корневой директории.
                    StartOfFileData = NumberOfReservedSectors * SectorSize + FatTableSizeInSectors * SectorSize * NumberOfFatCopies;

                    var offsetToFAT = NumberOfReservedSectors * SectorSize;

                    FAT = ReadFAT(offsetToFAT, (int)(FatTableSizeInSectors * SectorSize));

                    System.Windows.Forms.MessageBox.Show("Начато сканирование устройства.");

                    DriveDirectory root = new DriveDirectory("recovered");

                    ProcessDirectory(root, 2); //корневая директория - всегда 2 кластер.

                    System.Windows.Forms.MessageBox.Show("Сканирование завершено.");

                    rootRecover = root;

                    //тут нужно всё собрать.
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }
        //рекурсивный метод, строящий цепочку из директорий и содержащихся в них файлов
        private void ProcessDirectory(DriveDirectory directory, long claster)
        {
            //нумерация начинается с 2.
            //claster -= 2;

            #region calculateDirectoryData

            List <int>    ClastersOfThisDirectody = new List <int>(); //как оказалось, директории могут располагаться не в одном кластере.
            List <byte[]> clastersData            = new List <byte[]>();

            while (!IsClasterEOF((int)claster) && !IsClasterFreeInFAT((int)claster))
            {
                ClastersOfThisDirectody.Add((int)claster);
                clastersData.Add(Read((claster - 2) * ClasterSize, (int)ClasterSize));
                claster = GetNextClaster((int)claster);
            }
            ClastersOfThisDirectody.Add((int)claster);
            clastersData.Add(Read((claster - 2) * ClasterSize, (int)ClasterSize));

            var Data = clastersData[0]; //данные именно того кластера, который был передан в качестве параметра.

            for (int i = 1; i < clastersData.Count; i++)
            {
                Data = Unify(Data, clastersData[i]);
            }

            #endregion

            //читаем не с нулевой записи, потому что она указывает на текущую директорию. Нафиг надо.
            for (int i = 32; i < Data.Length - 32; i += 32)
            {
                try
                {
                    var attribute = GetAttribute(Data[i + 11]);

                    if (attribute == FileAttribute.Empty) //нечего читать.
                    {
                        break;
                    }

                    #region shortNameDirectory

                    if (attribute == FileAttribute.Directory)
                    {
                        StringBuilder dirName           = new StringBuilder();
                        long          CalculatedClaster = HexToDecimal(new byte[] { Data[i + 26], Data[i + 27], Data[i + 20], Data[i + 21] }); //кластер директории

                        dirName.Append(DecimalToASCII(Data, i + 1, i + 10));

                        if (Hex(Data[i + 0]).Contains("e5"))                 //удалённая директория.
                        {
                            dirName.Insert(0, 'Z');                          //символ, которым мы заменяем пустое место.

                            if (!IsClasterFreeInFAT((int)CalculatedClaster)) //если кластер, на который указывает директория, затёрт, то её не восстановить.
                            {
                                continue;
                            }
                        }
                        else
                        {
                            dirName.Insert(0, DecimalToASCII(Data, i + 0, i + 0));
                        }

                        if (dirName.ToString().Contains("..")) //если это указатель на верхнюю директорию, то уходим.
                        {
                            continue;
                        }

                        DriveDirectory dir = new DriveDirectory(dirName.ToString());
                        directory.Directories.Add(dir);

                        ProcessDirectory(dir, CalculatedClaster);
                    }

                    #endregion

                    #region shortNameFile

                    if (attribute == FileAttribute.Archive)
                    {
                        StringBuilder fileName = new StringBuilder();

                        fileName.Append(DecimalToASCII(Data, i + 1, i + 10));

                        if (Hex(Data[i]).Contains("e5"))
                        {
                            fileName.Insert(0, 'Z');

                            DriveFile file = new DriveFile();

                            file.Name = fileName.ToString();

                            long fileSize = CalculateSize(Data, i + 28, i + 31);

                            if (fileSize > MAX_RECOVERING_FILE_SIZE) //не восстанавливаем файлы слишком большого размера.
                            {
                                continue;
                            }

                            //число кластеров, в которых расположен файл.
                            var NumberOfClastersForLocating = fileSize / ClasterSize;

                            if (fileSize % ClasterSize != 0)
                            {
                                NumberOfClastersForLocating++;
                            }

                            var startClasterNumber = HexToDecimal(new byte[] { Data[i + 26], Data[i + 27], Data[i + 20], Data[i + 21] });

                            //ищем свободные кластеры, начиная с того кластера, на который указывает файл.
                            for (int j = (int)startClasterNumber; NumberOfClastersForLocating > 0 && j < FAT.Length / 4 - 2; j++)
                            {
                                if (IsClasterFreeInFAT(j))
                                {
                                    file.Clasters.Add(j);
                                    NumberOfClastersForLocating--;
                                }
                            }

                            if (NumberOfClastersForLocating == 0)
                            {
                                directory.Files.Add(file);
                            }
                        }
                        else
                        {
                            continue; //нечего восстанавливать, если у файла нет пометки.
                        }
                    }

                    #endregion

                    #region LFN

                    if (attribute == FileAttribute.LFN)
                    {
                        int j = i;

                        bool isDeleted = false; //если это имя относится к файлу, то файл должен быть удалён.

                        if (Hex(Data[j + 0]).Contains("e5"))
                        {
                            isDeleted = true;
                        }

                        StringBuilder name = new StringBuilder(" ");

                        //собираем длинное имя.
                        while (GetAttribute(Data[j + 11]) == FileAttribute.LFN && j < Data.Length - 32)
                        {
                            name.Insert(0, DecimalToUnicode(Data, j + 28, j + 31));
                            name.Insert(0, DecimalToUnicode(Data, j + 14, j + 25));
                            name.Insert(0, DecimalToUnicode(Data, j + 1, j + 10));

                            j += 32;
                        }


                        if (GetAttribute(Data[j + 11]) == FileAttribute.Directory)
                        {
                            var CalculatedClaster = HexToDecimal(new byte[] { Data[j + 26], Data[j + 27], Data[j + 20], Data[j + 21] });

                            DriveDirectory dir = new DriveDirectory(name.ToString());

                            if (isDeleted)
                            {
                                if (IsClasterFreeInFAT((int)CalculatedClaster))
                                {
                                    directory.Directories.Add(dir);
                                    ProcessDirectory(dir, CalculatedClaster);
                                }
                            }
                            else
                            {
                                directory.Directories.Add(dir);
                                ProcessDirectory(dir, CalculatedClaster);
                            }
                        }

                        if (GetAttribute(Data[j + 11]) == FileAttribute.Archive && isDeleted)
                        {
                            DriveFile file = new DriveFile(name.ToString());

                            var StartClasterNumber = HexToDecimal(new byte[] { Data[j + 26], Data[j + 27], Data[j + 20], Data[j + 21] });

                            long fileSize = CalculateSize(Data, j + 28, j + 31);

                            //число кластеров, в которых расположен файл.
                            var NumberOfClastersForLocating = fileSize / ClasterSize;

                            if (fileSize % ClasterSize != 0)
                            {
                                NumberOfClastersForLocating++;
                            }

                            if (fileSize < MAX_RECOVERING_FILE_SIZE)
                            {
                                for (int k = (int)StartClasterNumber; NumberOfClastersForLocating > 0 && k < FAT.Length / 4 - 2; k++)
                                {
                                    if (IsClasterFreeInFAT(k))
                                    {
                                        file.Clasters.Add(k);
                                        NumberOfClastersForLocating--;
                                    }
                                }

                                if (NumberOfClastersForLocating == 0)
                                {
                                    directory.Files.Add(file);
                                }
                            }
                        }

                        i = j;
                    }

                    #endregion
                }
                catch (IndexOutOfRangeException e)
                {
                    System.Windows.Forms.MessageBox.Show(e.Message); // за границу обычно номер кластера.
                }
                catch (ContextMarshalException e)
                {
                    i = (int)ClasterSize; // если мы словили неверный атрибут, когда ходили по директории, то директория была затёрта.
                }
                catch (Exception e)
                {
                    System.Windows.Forms.MessageBox.Show(e.Message);
                    continue;
                }
            }
        }
Example #4
0
 public DirectoryWithClaster(DriveDirectory directory, long claster)
 {
     Directory = directory;
     Claster   = claster;
 }