internal PartitionStream ReadStream(IBlobFileMetadata fileMetadata) { if (fileMetadata == null) { throw new ArgumentNullException("fileMetadata"); } if (fileMetadata.BlobStartPosition >= fileMetadata.BlobEndPosition) { throw new Exception(string.Format("Индекс начала файла не может быть равным или больше индекса окончания файла")); } //поток закрывает объект, предоставляющий средства потоковой передачи IBlobFileHeader fileHeader = (IBlobFileHeader)this.GetFileHeader(fileMetadata.BlobStartPosition); long contentStartPosition = fileMetadata.BlobStartPosition + BlobStreamAdapter.SystemHeaderLength + fileHeader.HeaderLength; PartitionStream stream = new PartitionStream(this.BlobStream, contentStartPosition, fileMetadata.Size); return(stream); }
public void Restore() { //проверяем поочередно каждый блоб каждого контейнера foreach (IBlobContainerMetadata containerMetadata in this.Containers) { try { //получаем все блобы контейнера ICollection <IBlobMetadata> blobs = this.DataAdapter.BlobMetadataAdapter.GetBlobs(containerMetadata.ID); if (blobs == null || blobs.Count == 0) { continue; } BlobContainer container = new BlobContainer(this.DataAdapter, containerMetadata); //Алгоритм восстановления метаданных //1 - получаем все блобы всех контейнеров //нужно посмотреть все блобы и закрытие и открытые. //потому что после запуска процедуры восстановления метаданных может пойти запись в не до конца восстановленный блоб //и он станет закрытым, но восстановление не завершилось. /*foreach (IBlobMetadata blobMetadata in blobs) * { * object tmp = blobMetadata.Closed; * }*/ //2 - для каждого блоба смотрим его позицию, до которой мы проверили целостность этого блоба foreach (IBlobMetadata blobMetadata in blobs) { Blob blob = new Blob(container, blobMetadata); try { long blobIntegrityPosition = blobMetadata.IntegrityPosition; long filelenth = blob.File.Length; //целостность метаданных файлов блоба до конца проверена while (blobIntegrityPosition < filelenth) { using (FileStream fs = blob.File.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { BlobStreamAdapter streamAdapter = new BlobStreamAdapter(fs); if (blobIntegrityPosition == 0) { //блоб может начинаться с системного заголовка. //а может с файла //тогда нужно сместить начальную позицию на этот системный заголовок //читаем позицию первого файла long firstFilePosition = streamAdapter.GetFirstFilePosition(); blob.UpdateIntegrityPosition(firstFilePosition); blobIntegrityPosition = blobMetadata.IntegrityPosition; } //заголовок из файла object fileHeaderObj = streamAdapter.GetFileHeader(blobIntegrityPosition); IFileHeader fileHeader = (IFileHeader)fileHeaderObj; IBlobFileHeader blobFileHeader = (IBlobFileHeader)fileHeaderObj; long fileStartPosition = blobMetadata.IntegrityPosition; if (fileStartPosition != blobFileHeader.ContentAbsoluteStartPosition) { throw new Exception(string.Format("Позиция целостности блоба не соответствует позиции начала файла")); } long fileEndPosition = fileStartPosition + BlobStreamAdapter.SystemHeaderLength + blobFileHeader.HeaderLength + blobFileHeader.ContentLength; //восстанавливаем метаданные, если их нет this.EnsureMetadata(blobMetadata, fileHeader, fileStartPosition, fileEndPosition); //увеличиваем позицию целостности метаданных блоба blob.UpdateIntegrityPosition(fileEndPosition); blobIntegrityPosition = blobMetadata.IntegrityPosition; } } } catch (Exception blobEx) { this.DataAdapter.Logger.WriteFormatMessage("Ошибка при восстановлении метаданных блоба с идентификатором {0} для контейнера {1}. Текст ошибки: {2}", blob.ID, containerMetadata.Path, blobEx); } } } catch (Exception containerEx) { this.DataAdapter.Logger.WriteFormatMessage("Ошибка при восстановлении метаданных контейнера {0}. Текст ошибки: {1}", containerMetadata.Path, containerEx); } } }
private byte[] ReadContent(Guid fileUniqueID, Guid fileVersionUniqueID, long blobStartPosition, long blobEndPosition) { if (fileUniqueID == Guid.Empty) { throw new ArgumentNullException("fileUniqueID"); } if (fileVersionUniqueID == Guid.Empty) { throw new ArgumentNullException("fileVersionUniqueID"); } if (blobStartPosition < 0) { throw new ArgumentNullException("blobStartPosition"); } if (blobEndPosition < 1) { throw new ArgumentNullException("blobEndPosition"); } if (blobStartPosition >= blobEndPosition) { throw new Exception(string.Format("Индекс начала файла не может быть равным или больше индекса окончания файла")); } long length = blobEndPosition - blobStartPosition; if (blobEndPosition > this.BlobStream.Length) { throw new IndexOutOfRangeException("Индекс окончания файла превысил размер блоба"); } //сырые данные файла (со всеми заголовками и хешами) byte[] rawData = new byte[length]; if (length > Int32.MaxValue) { throw new Exception(string.Format("Файлы размером более 2GB в данный момент не поддерживаются")); } else { this.BlobStream.Seek(blobStartPosition, SeekOrigin.Begin); this.BlobStream.Read(rawData, 0, rawData.Length); } //1 - проверка системного префикса. //системный заголовок занимает первые _systemHeaderLength байт for (int i = 0; i < SystemHeaderFixedBytes.Length; i++) { if (SystemHeaderFixedBytes[i] != rawData[i]) { throw new Exception(string.Format("Битый заголовок файла (позиция {0}). Не удалось прочитать системный заголовок файла.", i)); } } //проверка заголовка. object header = this.GetFileHeader(rawData); IBlobFileHeader blobHeader = (IBlobFileHeader)header; long contentLength = blobHeader.ContentLength; if (contentLength == 0) { throw new Exception(string.Format("Не удалось считать размер содержимого файла")); } byte[] content = new byte[contentLength]; Array.Copy(rawData, BlobStreamAdapter.SystemHeaderLength + blobHeader.HeaderLength, content, 0, contentLength); //проверка идентификаторов версий IFileHeader fileHeader = (IFileHeader)header; if (fileUniqueID != fileHeader.UniqueID) { throw new Exception(string.Format("Идентификатор файла в метаданных не совпадает с идентификатором файла в блобе")); } if (fileVersionUniqueID != fileHeader.VersionUniqueID) { throw new Exception(string.Format("Идентификатор версии файла в метаданных не совпадает с идентификатором версии файла в блобе")); } byte[] originalHeaderHash = new byte[16];//хеш заголовка файла из самого блоба Array.Copy(rawData, SystemHeaderFixedBytes.Length + BlobConsts.BlobFile.HeaderSizeBytesLength, originalHeaderHash, 0, originalHeaderHash.Length); //хеш вычисленный по байтам заголовка byte[] currentHeaderHash = this.HashAlgorithm.ComputeHash(rawData, BlobStreamAdapter.SystemHeaderLength, blobHeader.HeaderLength); bool headerHashInvalid = !originalHeaderHash.SequenceEqual(currentHeaderHash); if (headerHashInvalid) { throw new Exception(string.Format("Битый заголовок файла. Не удалось прочитать системный заголовок файла.")); } //3 - проверка хеша содержимого. byte[] originalContentHash = new byte[16];//хеш содержимого файла из самого блоба Array.Copy(rawData, SystemHeaderFixedBytes.Length + BlobConsts.BlobFile.HeaderSizeBytesLength + originalHeaderHash.Length, originalContentHash, 0, originalContentHash.Length); byte[] currentContentHash = this.HashAlgorithm.ComputeHash(content); bool contentHashInvalid = !originalContentHash.SequenceEqual(currentContentHash); if (contentHashInvalid) { throw new Exception(string.Format("Битое содержимое файла. Не удалось прочитать содержимое файла.")); } rawData = null; originalHeaderHash = null; currentHeaderHash = null; originalContentHash = null; currentContentHash = null; return(content); }
/// <summary> /// Создает метаданные существующего файла. /// </summary> /// <param name="storageMetadata">Метаданные хранилища.</param> /// <param name="blobMetadata">Метаданные блоба.</param> /// <param name="folderMetadata">Метаданные папки.</param> /// <param name="fileHeader">Заголовок файла.</param> /// <param name="blobStartPosition">Начальная позиция файла в блобе.</param> /// <param name="blobEndPosition">Конечная позиция файла в блобе.</param> /// <returns></returns> public IBlobFileMetadata AddExistsFileVersion(IStorageMetadata storageMetadata, IBlobMetadata blobMetadata, IFolderMetadata folderMetadata, IFileHeader fileHeader, long blobStartPosition, long blobEndPosition) { if (storageMetadata == null) { throw new ArgumentNullException("storageMetadata"); } if (blobMetadata == null) { throw new ArgumentNullException("blobMetadata"); } if (folderMetadata == null) { throw new ArgumentNullException("folderMetadata"); } if (fileHeader == null) { throw new ArgumentNullException("fileHeader"); } if (blobStartPosition < 0) { throw new ArgumentNullException("blobStartPosition"); } IBlobFileHeader blobHeader = (IBlobFileHeader)((object)fileHeader); FileMetadata file = this.FileAdapter.GetFile(fileHeader.UniqueID, folderMetadata); bool justCreated = false; if (file == null) { justCreated = true; file = new FileMetadata(this.FileAdapter); file.UniqueID = fileHeader.UniqueID; file.VersionUniqueID = fileHeader.VersionUniqueID; file.FolderID = folderMetadata.ID; file.FolderMetadata = folderMetadata; file.Name = fileHeader.FileName; file.BlobID = blobMetadata.ID; file.BlobStartPosition = blobStartPosition; file.BlobEndPosition = blobEndPosition; file.Deleted = false; file.Size = blobHeader.ContentLength; file.TimeCreated = fileHeader.TimeCreated; file.TimeModified = fileHeader.TimeCreated; this.FileAdapter.UpdateFileTransparent(file); } else { if (file.Versions.Any(x => x.UniqueID == fileHeader.VersionUniqueID)) { throw new Exception(String.Format("Версия с идентификатором [{0}] уже существует.", fileHeader.VersionUniqueID.ToString())); } } //создание версии файла FileVersionMetadata version = new FileVersionMetadata(file); version.UniqueID = fileHeader.VersionUniqueID; version.BlobID = blobMetadata.ID; version.BlobStartPosition = blobStartPosition; version.BlobEndPosition = blobEndPosition; version.Size = blobHeader.ContentLength; version.TimeCreated = fileHeader.TimeCreated; version.CreatedStorageID = storageMetadata.ID; version.Name = fileHeader.FileName; //сохранение версии this.FileAdapter.VersionAdapter.InsertVerion(file, version); file.ResetVersions(); //обновление параметров существующего файла if (!justCreated) { bool fileUpdate = false; if (version.TimeCreated > file.TimeModified) { file.TimeModified = version.TimeCreated; file.VersionUniqueID = version.UniqueID; file.BlobID = version.BlobID; fileUpdate = true; } if (version.TimeCreated < file.TimeCreated) { file.TimeCreated = version.TimeCreated; fileUpdate = true; } //обновление файла if (fileUpdate) { this.FileAdapter.UpdateFileTransparent(file); } } return(file); }