public byte[] CalculateContentHashSingle(DirectoryInfo directory, Predicate <FileSystemInfo> excludePredicate = null)
        {
            byte[] hash = new byte[20];
            try
            {
                foreach (var fileSystemInfo in directory.EnumerateFileSystemInfos())
                {
                    if (excludePredicate != null && excludePredicate(fileSystemInfo))
                    {
                        continue;
                    }

                    if (fileSystemInfo is FileInfo fileInfo)
                    {
                        hash.AddHash(CalculateMetadataHash(fileInfo));
                        using (var file = fileInfo.OpenRead())
                        {
                            hash.AddHash(CalculateContentHash(file));
                        }
                    }
                    else if (fileSystemInfo is DirectoryInfo directoryInfo)
                    {
                        hash.AddHash(CalculateMetadataHash(directoryInfo));
                        hash.AddHash(CalculateContentHash(directoryInfo, excludePredicate));
                    }
                }
            }
            catch (Exception exception)
            {
                Log.Error(exception, "Error while computing directory content Hash (Dir: {directory})", directory.FullName);
                throw;
            }
            return(hash);
        }
        public byte[] CalculateMetadataOnlyHash(DirectoryInfo directory, Predicate <FileSystemInfo> excludePredicate = null)
        {
            byte[] hash = new byte[20];
            foreach (var fileSystemInfo in directory.EnumerateFileSystemInfos())
            {
                if (excludePredicate != null && excludePredicate(fileSystemInfo))
                {
                    continue;
                }

                if (fileSystemInfo is FileInfo fileInfo)
                {
                    hash.AddHash(CalculateMetadataHash(fileInfo));
                }
                else if (fileSystemInfo is DirectoryInfo directoryInfo)
                {
                    hash.AddHash(CalculateMetadataHash(directoryInfo));
                }
            }

            return(hash);
        }
        private byte[] CalculateL1Hash(Span <byte[]> l0Hashes, SHA1 sha1)
        {
            if (!IsEmpty(l0Hashes))
            {
                var hash = new byte[20];
                for (int i = 0; i < l0Hashes.Length; i++)
                {
                    if (l0Hashes[i] != null)
                    {
                        hash.AddHash(CalculateIndexedHash(l0Hashes[i], i, sha1));
                    }
                }
                return(hash);
            }

            return(null);
        }
        public byte[] CalculateContentHash(DirectoryInfo directory, Predicate <FileSystemInfo> excludePredicate = null)
        {
            var lockObject = new object();

            byte[] hash = new byte[20];
            try
            {
                //Parallel.ForEach(directory.EnumerateFileSystemInfos(), new ParallelOptions {MaxDegreeOfParallelism = 2},
                //    fileSystemInfo =>
                //    {
                //        if (excludePredicate != null && excludePredicate(fileSystemInfo))
                //        {
                //            return;
                //        }

                //        if (fileSystemInfo is FileInfo fileInfo)
                //        {
                //            var metadataHash = CalculateMetadataHash(fileInfo);
                //            using (var file = fileInfo.OpenRead())
                //            {
                //                var contentHash = CalculateContentHash(file);
                //                metadataHash.AddHash(contentHash);
                //            }

                //            lock (metadataHash)
                //            {

                //            }
                //        }
                //        else if (fileSystemInfo is DirectoryInfo directoryInfo)
                //        {
                //            hash.AddHash(CalculateMetadataHash(directoryInfo));
                //            hash.AddHash(CalculateContentHash(directoryInfo, excludePredicate));
                //        }
                //    });

                Parallel.ForEach(directory.EnumerateFileSystemInfos(), new ParallelOptions {
                    MaxDegreeOfParallelism = 8
                }, () => new byte[20], (fileSystemInfo, state, arg3) =>
                                 //fileSystemInfo =>
                {
                    //var h = new byte[20];
                    //h.AddHash(arg3);
                    if (excludePredicate == null || !excludePredicate(fileSystemInfo))
                    {
                        if (fileSystemInfo is FileInfo fileInfo)
                        {
                            var metadataHash = CalculateMetadataHash(fileInfo);
                            arg3.AddHash(metadataHash);
                            //h.AddHash(metadataHash);
                            using (var file = fileInfo.OpenRead())
                            {
                                var contentHash = CalculateContentHash(file);
                                arg3.AddHash(contentHash);
                                //metadataHash.AddHash(contentHash);
                                //h.AddHash(contentHash);
                            }
                            //arg3.Add(metadataHash);
                        }
                        if (fileSystemInfo is DirectoryInfo directoryInfo)
                        {
                            var metadataHash = CalculateMetadataHash(directoryInfo);
                            arg3.AddHash(metadataHash);
                            //h.AddHash(metadataHash);
                            var contentHash = CalculateContentHash(directoryInfo, excludePredicate);
                            //h.AddHash(contentHash);
                            //metadataHash.AddHash(contentHash);
                            arg3.AddHash(contentHash);
                        }
                    }

                    return(arg3);
                }, bytes =>
                {
                    lock (lockObject)
                    {
                        hash.AddHash(bytes);
                    }
                });

                //foreach (var fileSystemInfo in directory.EnumerateFileSystemInfos())
                //{
                //    if (excludePredicate != null && excludePredicate(fileSystemInfo))
                //    {
                //        continue;
                //    }

                //    if (fileSystemInfo is FileInfo fileInfo)
                //    {
                //        hash.AddHash(CalculateMetadataHash(fileInfo));
                //        using (var file = fileInfo.OpenRead())
                //        {
                //            hash.AddHash(CalculateContentHash(file));
                //        }
                //    }
                //    else if (fileSystemInfo is DirectoryInfo directoryInfo)
                //    {
                //        hash.AddHash(CalculateMetadataHash(directoryInfo));
                //        hash.AddHash(CalculateContentHash(directoryInfo, excludePredicate));
                //    }
                //}
            }
            catch (Exception exception)
            {
                Log.Error(exception, "Error while computing directory content Hash (Dir: {directory})", directory.FullName);
                throw;
            }
            return(hash);
        }