// Функция резервирует базу данных по указанному пути. Таблицы должны распологаться в таком порядке, что бы первыми шли таблицы которые не ссылаются на другие.
        public bool Write(string path, Log log)
        {
            var flag = true;

            FileStream stream_meta = null;
            FileStream stream_data = null;

            // Стартовая позиция метаданных таблиц
            var meta_start = 0l;

            // Размер метаданных
            var meta_size = 0;

            try
            {
                var dt = DateTime.Now;

                log.Append("Backup begin at ");
                log.Append(dt.ToString("F"));
                log.Append("\r\n");

                stream_meta = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
                stream_data = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);

                var sm      = new BinaryWriterCRC32(stream_meta);
                var sd      = new BinaryWriter(stream_data);
                var counts  = new int[DB.Tables.Count];
                var version = Assembly.GetCallingAssembly().GetName().Version;

                // Запись типа бекапа
                sm.Write(1);
                // Запись времени бекапа
                sm.Write(dt.Ticks);
                // Запись версии базы
                sm.Write(DB.Version);
                // Запись версии кода
                sm.Write(version.Major);
                sm.Write(version.Minor);
                sm.Write(version.Build);
                sm.Write(version.Revision);
                // Запись количества таблиц
                sm.Write(DB.Tables.Count);

                // Оставляем шапку 1024 байта
                stream_meta.Position = 1024;

                // crc шапки
                sm.WriteAndResetCRC();

                // Записываем структуру таблиц
                for (int i = 0; i < DB.Tables.Count; ++i)
                {
                    var itm = DB.Tables[i];

                    // Количество
                    sm.Write(itm.File.Count);
                    // Позиция в файле
                    sm.Write(meta_size);
                    // Название таблицы
                    sm.Write(itm.Key);
                    // Версия таблицы
                    sm.Write(itm.CurrentVersion.Version);
                    // Размер таблицы
                    sm.Write(itm.CurrentVersion.RecordSize);
                    // Режим записи
                    sm.Write((int)itm.CurrentVersion.Mode);
                    // Массивы произвольной длинны
                    sm.Write(itm.CurrentVersion.HasStorage);
                    // Количество полей
                    sm.Write(itm.CurrentVersion.Structure.Length);
                    // Поля
                    for (var j = 0; j < itm.CurrentVersion.Structure.Length; ++j)
                    {
                        var fld = itm.CurrentVersion.Structure[j];

                        sm.Write(fld.IsStorage);
                        sm.Write(fld.Name);
                        sm.Write(fld.Size);
                        sm.Write(fld.Offset);
                    }

                    // Размер мета
                    meta_size += itm.File.Count * 8 + 4;
                    // CRC записи
                    sm.WriteAndResetCRC();

                    counts[i] = itm.File.Count;
                }

                // Инициализируем место для метаданых
                meta_start           = stream_meta.Position;
                stream_data.Position = meta_start + meta_size;

                // Записываем даные
                for (int i = 0; i < DB.Tables.Count; ++i)
                {
                    var itm = DB.Tables[i];

                    flag &= WriteTable(itm, sm, sd, counts[i], log);

                    // CRC метаданных таблицы
                    sm.WriteAndResetCRC();
                }
            }
            catch (Exception e)
            {
                flag = false;

                log.Append(e);
            }
            finally
            {
                //var wtf = stream_data.Position;
                //stream_data.Position = Backup.TestPosition;
                //var br = new BinaryReader(stream_data);
                //var ppc = br.ReadInt32();
                //stream_data.Position = wtf;
                //Debug.WriteLine("Final Control: " + ppc);

                if (stream_meta != null)
                {
                    if (stream_meta.Position != meta_start + meta_size)
                    {
                        flag = false;

                        log.Append("Stream metada is oversized.");
                    }


                    stream_meta.Close();
                }

                if (stream_data != null)
                {
                    stream_data.Close();
                }
            }

            log.Append("\r\n");

            if (flag)
            {
                log.Append("Backup DONE");
            }
            else
            {
                log.Append("Backup FAIL");
            }

            return(flag);
        }
        // Функция копирует данные таблицы в бекап
        bool WriteTable(ITable itm, BinaryWriterCRC32 sm, BinaryWriter sd, int count, Log log)
        {
            log.Append("Begin read table: ");
            log.Append(itm.Key);
            log.Append(", count: ");
            log.Append(count);
            log.Append("\r\n");

            var crc     = new CRC32();
            var crcerr  = 0;
            var crcused = (itm.CurrentVersion.Mode & PageFileIOMode.CRC32) == PageFileIOMode.CRC32;
            var fs      = itm.File.CreateStream();
            var size    = itm.CurrentVersion.RecordSize;
            var buf     = new byte[size];
            var map     = itm.File.GetDeletedMap();
            var ver     = itm.CurrentVersion;
            var delta   = size_time;
            var flag    = true;

            if (crcused)
            {
                delta = size_time_crc;
            }

            fs.Position = PageFile.HeaderSize + size;

            for (int i = 0; i < count; ++i)
            {
                // Записываем позицию метаданных
                sm.Write(sd.BaseStream.Position);

                //Debug.WriteLine("Backup " + itm.Key + ", code: " + (i + 1) + ", offset:" + sd.BaseStream.Position);

                fs.Read(buf, 0, size);

                if (i + 1 == 1350685)
                {
                    var bp = 0;
                }

                var time = 0l;
                var fact = 0l;

                // Читаем время и crc
                fixed(byte *ptr = &buf[size - delta])
                {
                    time = *(long *)ptr;

                    if (crcused)
                    {
                        fact = *(int *)(ptr + size_time);
                    }
                }

                // Пишем время
                if (map.Contains(i + 1))
                {
                    if (time == 0)
                    {
                        time = DateTime.Now.Ticks;
                    }

                    // если запись удалена
                    sd.Write(-time);

                    crc.Reset();

                    continue;
                }
                else
                {
                    // если запись нормальная
                    sd.Write(time);
                }

                // считаем crc данных и времени
                crc.Update(buf, 0, size - delta);
                crc.Update(time);

                // Быстрая проверка без данных переменной длинны
                if (fact != crc.Value)
                {
                    flag = false;

                    crcerr++;

                    if (crcerr < 10)
                    {
                        log.Append("Warning reading: The object with code: ", i + 1, " crc32 check failed.\r\n");
                    }
                }

                crc.Reset();
                crc.Update(time);

                // Массивы произвольной длинны
                if (ver.HasStorage)
                {
                    for (var j = 0; j < ver.Structure.Length; ++j)
                    {
                        var fld = ver.Structure[j];

                        if (fld.IsStorage)
                        {
                            //Debug.WriteLine("Backup " + itm.Key + ", code: " + (i + 1) + ", field: " + fld.Name + " pos: " + sd.BaseStream.Position);

                            fixed(byte *ptr = &buf[fld.Offset])
                            {
                                var tmp = fld.Storage.ReadBytes(*((long *)ptr));

                                sd.Write(tmp.Length);
                                sd.BaseStream.Write(tmp, 0, tmp.Length);

                                crc.Update(tmp.Length);
                                crc.Update(tmp, 0, tmp.Length);
                            }
                        }
                        else
                        {
                            switch (fld.Size)
                            {
                            case 1:
                            {
                                sd.Write(buf[fld.Offset]);
                                crc.Update(buf[fld.Offset]);

                                break;
                            }

                            case 2:
                            {
                                fixed(byte *ptr = &buf[fld.Offset])
                                {
                                    var tmp = (char *)ptr;

                                    sd.Write(*tmp);
                                    crc.Update(*tmp);
                                }

                                break;
                            }

                            case 4:
                            {
                                fixed(byte *ptr = &buf[fld.Offset])
                                {
                                    var tmp = (uint *)ptr;

                                    sd.Write(*tmp);
                                    crc.Update(*tmp);
                                }

                                break;
                            }

                            case 8:
                            {
                                fixed(byte *ptr = &buf[fld.Offset])
                                {
                                    var tmp = (ulong *)ptr;

                                    sd.Write(*tmp);
                                    crc.Update(*tmp);
                                }

                                break;
                            }

                            case 16:
                            {
                                fixed(byte *ptr = &buf[fld.Offset])
                                {
                                    var tmp = (decimal *)ptr;

                                    sd.Write(*tmp);
                                    crc.Update(*tmp);
                                }

                                break;
                            }
                            }
                        }
                    }

                    // Пишем CRC
                    sd.Write(crc.Value);
                }
                else
                {
                    // crc данных
                    crc.Update(buf, 0, size - delta);

                    // Пишем данные
                    sd.BaseStream.Write(buf, 0, size - delta);
                    // Пишем CRC
                    sd.Write(crc.Value);
                }

                crc.Reset();

                if (i > 0 && i % 100000 == 0)
                {
                    log.Append("Progresss : ", i, "\r\n");
                }
            }

            fs.Close();

            return(flag);
        }