예제 #1
0
        /// <summary>
        /// </summary>
        /// <param name="File"></param>
        /// <param name="Offset"></param>
        /// <param name="Size"></param>
        /// <returns></returns>
        public bool GetBlockInfo(int Index, ref BuildManifestBlockInfo Info)
        {
            LazyCacheBlockInfo();

            if (Index < 0 || Index >= BlockCount)
            {
                throw new ArgumentOutOfRangeException("Index", "Block index out of range.");
            }

            Info = BlockInfo[Index];
            return(true);
        }
예제 #2
0
        /// <summary>
        /// </summary>
        /// <param name="Index"></param>
        /// <returns></returns>
        public bool GetBlockData(int Index, string RootPath, AsyncIOQueue IOQueue, byte[] Data, out long DataLength)
        {
            LazyCacheBlockInfo();

            DataLength = 0;

            if (Index < 0 || Index >= BlockCount)
            {
                throw new ArgumentOutOfRangeException("Index", "Block index out of range.");
                return(false);
            }

            BuildManifestBlockInfo Info = BlockInfo[Index];

            Debug.Assert(Data.Length >= Info.TotalSize);
            DataLength = Info.TotalSize;

            ManualResetEvent CompleteEvent = new ManualResetEvent(false);
            int QueuedReads = Info.SubBlocks.Length;

            bool Success = true;

            foreach (BuildManifestSubBlockInfo SubBlock in Info.SubBlocks)
            {
                string PathName = Path.Combine(RootPath, SubBlock.File.Path);
                IOQueue.Read(
                    PathName, SubBlock.FileOffset, SubBlock.FileSize, Data, SubBlock.OffsetInBlock, bSuccess =>
                {
                    int Result = Interlocked.Decrement(ref QueuedReads);
                    if (Result == 0)
                    {
                        CompleteEvent.Set();
                    }

                    if (!bSuccess)
                    {
                        Success = false;

                        Logger.Log(LogLevel.Error, LogCategory.Manifest, "Failed to read data for block (offset={0} size={1}) from file {2}", SubBlock.FileOffset, SubBlock.FileSize, SubBlock.File);
                    }
                }
                    );
            }

            CompleteEvent.WaitOne();

            return(Success);
        }
예제 #3
0
        /// <summary>
        /// </summary>
        public List <int> Validate(string RootPath, RateTracker Tracker, AsyncIOQueue IOQueue, BuildManfiestValidateProgressCallbackHandler Callback = null)
        {
            LazyCacheBlockInfo();

            List <int> FailedBlocks = new List <int>();

            try
            {
                LockBlockInfo();

                int    TaskCount    = Environment.ProcessorCount;
                Task[] FileTasks    = new Task[TaskCount];
                int    BlockCounter = 0;

                long BytesValidated = 0;
                bool Aborted        = false;

                // Check the size of each file.
                for (int i = 0; i < Files.Count; i++)
                {
                    BuildManifestFileInfo FileInfo = Files[i];
                    string FilePath = Path.Combine(RootPath, FileInfo.Path);
                    string DirPath  = Path.GetDirectoryName(FilePath);

                    if (!Directory.Exists(DirPath))
                    {
                        Directory.CreateDirectory(DirPath);
                        Logger.Log(LogLevel.Warning, LogCategory.Manifest, "Expected directory {0} does not exist, creating.", DirPath);
                    }

                    FileInfo Info = new FileInfo(FilePath);
                    if (!Info.Exists || Info.Length != FileInfo.Size)
                    {
                        using (FileStream Stream = new FileStream(FilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
                        {
                            Logger.Log(LogLevel.Warning, LogCategory.Manifest, "File {0} is not of expected length {1} (is {2}) settting length.", FilePath, FileInfo.Size, Info.Length);
                            Stream.SetLength(FileInfo.Size);
                        }
                    }
                }

                // Check each individual block of data for validity.
                for (int i = 0; i < TaskCount; i++)
                {
                    FileTasks[i] = Task.Run(
                        () =>
                    {
                        byte[] Buffer = new byte[BlockSize];

                        while (!Aborted)
                        {
                            int BlockIndex = Interlocked.Increment(ref BlockCounter) - 1;
                            if (BlockIndex >= BlockCount)
                            {
                                break;
                            }

                            BuildManifestBlockInfo BInfo = BlockInfo[BlockIndex];

                            long BufferLength = 0;
                            bool Success      = GetBlockData(BlockIndex, RootPath, IOQueue, Buffer, out BufferLength);

                            uint Checksum = 0;
                            if (Version >= 2)
                            {
                                Checksum = Crc32Fast.Compute(Buffer, 0, (int)BufferLength);
                            }
                            else
                            {
                                Checksum = Crc32Slow.Compute(Buffer, (int)BufferLength);
                            }

                            if (!Success || BlockChecksums[BlockIndex] != Checksum)
                            {
                                Logger.Log(LogLevel.Warning, LogCategory.Manifest, "Block {0} failed checksum, block contains following sub-blocks:", BlockIndex);

                                for (int SubBlock = 0; SubBlock < BInfo.SubBlocks.Length; SubBlock++)
                                {
                                    BuildManifestSubBlockInfo SubBInfo = BInfo.SubBlocks[SubBlock];
                                    Logger.Log(LogLevel.Warning, LogCategory.Manifest, "\tfile={0} offset={1} size={2}", SubBInfo.File.Path, SubBInfo.FileOffset, SubBInfo.FileSize);
                                }

                                lock (FailedBlocks)
                                {
                                    FailedBlocks.Add(BlockIndex);
                                }
                            }

                            Interlocked.Add(ref BytesValidated, BInfo.TotalSize);

                            if (Callback != null)
                            {
                                if (!Callback.Invoke(BytesValidated, TotalSize, Guid, BlockIndex))
                                {
                                    Aborted = true;
                                }
                            }
                        }
                    }
                        );
                }

                Task.WaitAll(FileTasks);
            }
            finally
            {
                UnlockBlockInfo();
            }

            return(FailedBlocks);
        }