private static void LoadDirectoryContent(IDirectory direct,
                                                 ExtPartInfo partInfo,
                                                 Action <long> ntfSzAct,
                                                 Func <bool> isCancel)
        {
            var dirStoken   = direct.GetStoken(Constants.DirectoryKey_Ext);
            var fatFileInfo = dirStoken.GetInstance <ExtFileInfo>(Constants.FileStokenTag_ExtFileInfo) as ExtFileInfo;

            var filePtr = ExtX_Parse_Dir(partInfo.ExtUnmanagedManager.ExtManagerPtr, fatFileInfo.BlockListPtr);

            DealWithFileNode(direct, partInfo, filePtr, ntfSzAct, isCancel);
        }
        public IFile ParseStream(Stream stream, string name, IProgressReporter reporter)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            var part   = FileFactory.CreatePartition(Constants.PartitionKey_Ext);
            var stoken = part.GetStoken(Constants.PartitionKey_Ext);

            stoken.BaseStream = stream;
            stoken.Name       = name;
            stoken.Size       = stream.Length;
            stoken.TypeGuid   = Constants.PartitionType_Ext;

            var extUnmanagedManager = new ExtUnmanagedManager(stream);
            var partInfo            = new ExtPartInfo {
                ExtUnmanagedManager = extUnmanagedManager
            };

#if DEBUG
            //IntPtr stExt4Inode = ExtX_Get_InodeInfo(extUnmanagedManager.ExtManagerPtr, 113880);    //129793
            //var stBlockList = ExtX_Get_BlockList(extUnmanagedManager.ExtManagerPtr, stExt4Inode);
            //var stDirDntry = ExtX_Parse_Dir(extUnmanagedManager.ExtManagerPtr, stBlockList);
            //var dirEntry = stDirDntry.GetStructure<StDirEntry>();
            //var cext4Entry = dirEntry.DirInfo.GetStructure<StExt4DirEntry>();
#endif
            //设定EXT分区详细信息;
            stoken.SetInstance(partInfo, Constants.PartitionStokenTag_ExtPartInfo);
            stoken.PartType = ServiceProvider.GetAllInstances <IPartitionType>().FirstOrDefault(p => p.GUID == Constants.PartitionType_Ext);
            if (partInfo.ExtUnmanagedManager.ExtManagerPtr == IntPtr.Zero)
            {
                extUnmanagedManager.Dispose();
                throw new InvalidOperationException($"{nameof(extUnmanagedManager.ExtManagerPtr)} can't be nullptr.");
            }

            try {
                LoadPartInfo(partInfo);
                LoadPartContent(part, reporter);
            }
            catch (Exception ex) {
                LoggerService.WriteException(ex);
            }

            part.Disposing += OnPart_Disposing;

            return(part);
        }
        private static void LoadPartInfo(ExtPartInfo partInfo)
        {
            if (partInfo == null)
            {
                throw new ArgumentNullException(nameof(partInfo));
            }

            var stSuperBlockPtr = ExtX_SuperBlock(partInfo.ExtUnmanagedManager.ExtManagerPtr);

            if (stSuperBlockPtr == IntPtr.Zero)
            {
                //LoggerService.WriteCallerLine($"{nameof(stSuperBlockPtr)} can't be nullptr.");
                return;
            }
            else
            {
                partInfo.SuperBlock = new SuperBlock(stSuperBlockPtr.GetStructure <StSuperBlock>());
            }

            var stGroupDescPtr = ExtX_GroupDesc(partInfo.ExtUnmanagedManager.ExtManagerPtr);

            if (stGroupDescPtr == IntPtr.Zero)
            {
                //LoggerService.WriteCallerLine($"{nameof(stGroupDescPtr)} can't be nullptr.");
                return;
            }
            else
            {
                var descIndex = 0;
                partInfo.Ext4GroupDescs = stGroupDescPtr.GetStructs <StExtGroupDesc>(p => p.Next)?.
                                          Select(p => {
                    var desc = new ExtGroupDesc(p)
                    {
                        InternalDisplayName = $"{LanguageService.FindResourceString(Constants.DisplayName_ExtGroupDesc)}{++descIndex}"
                    };
                    return(desc);
                }).ToArray() ?? null;
            }

            //stExt4INodePtr = ExtX_Get_InodeInfo( 2);                  //加载Inode,BlockList,Dir;
            //stBlockListPtr = Cflabqd_Get_BlockList(stExt4INodePtr);     //加载Inode,BlockList,Dir;
            //stDirEntryPtr = Cflabqd_Parse_Dir(stBlockListPtr);            //加载Inode,BlockList,Dir;
        }
        /// <summary>
        /// 编辑目录/文件/其它的时间,簇列表等值;
        /// </summary>
        /// <param name="fileStoken2"></param>
        private static void EditFileStoken2(
            FileStokenBase2 fileStoken2,
            ExtPartInfo partInfo,
            ExtFileInfo extFileInfo)
        {
            if (fileStoken2 == null)
            {
                throw new ArgumentNullException(nameof(fileStoken2));
            }

            if (extFileInfo == null)
            {
                throw new ArgumentNullException(nameof(extFileInfo));
            }

            if (extFileInfo.BlockListPtr == null)
            {
                throw new InvalidOperationException($"{nameof(extFileInfo.BlockListPtr)} of {nameof(ExtFileInfo)} can't be nullptr.");
            }

            if (partInfo == null)
            {
                throw new ArgumentNullException(nameof(partInfo));
            }

            fileStoken2.SetInstance(extFileInfo, Constants.FileStokenTag_ExtFileInfo);

            fileStoken2.Name    = extFileInfo.StExt4DirEntry?.Name;
            fileStoken2.Size    = extFileInfo.StExt4Inode?.Size ?? 0;
            fileStoken2.Deleted = extFileInfo.StDirEntry?.bDel ?? false;

            EditTime(fileStoken2, extFileInfo);
#if DEBUG
            //if (fileStoken2.Name.StartsWith(".journal")) {

            //}
#endif
            EditBlockGroups(fileStoken2, partInfo, extFileInfo);
        }
        /// <summary>
        /// 编辑块组;
        /// </summary>
        /// <param name="fileStoken2"></param>
        /// <param name="partInfo"></param>
        /// <param name="extFileInfo"></param>
        private static void EditBlockGroups(
            FileStokenBase2 fileStoken2,
            ExtPartInfo partInfo,
            ExtFileInfo extFileInfo)
        {
            if (fileStoken2 == null)
            {
                throw new ArgumentNullException(nameof(fileStoken2));
            }

            if (extFileInfo == null)
            {
                throw new ArgumentNullException(nameof(extFileInfo));
            }

            //if (extFileInfo.BlockListPtr == null) {
            //    throw new InvalidOperationException($"{nameof(extFileInfo.BlockListPtr)} of {nameof(ExtFileInfo)} can't be nullptr.");
            //}

            if (partInfo == null)
            {
                throw new ArgumentNullException(nameof(partInfo));
            }

            if (extFileInfo.BlockList == null)
            {
                //LoggerService.WriteCallerLine($"{nameof(extFileInfo.BlockList)} can't be null.");
                return;
            }

            var blocks    = extFileInfo.BlockList;
            var blockSize = partInfo.SuperBlock.StructInstance.BlockSize;

            if (blocks == null)
            {
                return;
            }

            //遍历,粘合,将连续的簇列表并入为一个块组;
            StBlockList?lastBlock       = null;
            long        firstClusterLBA = 0;

            int   blockCount   = 0;
            ulong lastBlockNum = 0;

            //重置局部变量;参数为本次(循环)最新的独立头块;
            void Reset(StBlockList block)
            {
                lastBlock       = block;
                blockCount      = (int)block.count;
                lastBlockNum    = block.address;
                firstClusterLBA = (long)block.address * blockSize;
            }

            //压栈;
            void PushBlockGroup()
            {
                if (lastBlock == null)
                {
                    return;
                }

                fileStoken2.BlockGroups.Add(
                    BlockGroupFactory.CreateNewBlockGroup((long)lastBlock.Value.address, blockCount, blockSize, firstClusterLBA)
                    );
            }

            try {
                foreach (var cluster in blocks)
                {
                    if (lastBlock == null)
                    {
                        Reset(cluster);
                        continue;
                    }

                    //如果是连续的簇号则+1;
                    if (cluster.address == lastBlockNum + 1)
                    {
                        lastBlockNum = cluster.address;
                        blockCount++;
                    }
                    //否则,构造BlockGroup,插入新建链表,并重置;
                    else
                    {
                        PushBlockGroup();
                        Reset(cluster);
                    }
                }

                if (lastBlock != null)
                {
                    PushBlockGroup();
                }
            }
            catch (Exception ex) {
                LoggerService.WriteCallerLine(ex.Message);
            }
        }
        /// <summary>
        /// 处理子文件/目录/其它加载;
        /// </summary>
        /// <param name="haveFileCollection"></param>
        /// <param name="filePtr">非托管文件节点指针</param>
        /// <param name="ntfSzAct"></param>
        /// <param name="isCancel"></param>
        private static void DealWithFileNode(
            IHaveFileCollection haveFileCollection,
            ExtPartInfo partInfo,
            IntPtr filePtr,
            Action <long> ntfSzAct,
            Func <bool> isCancel)
        {
            while (filePtr != IntPtr.Zero)
            {
                IFile           file        = null;
                FileStokenBase2 fileStoken2 = null;
                var             stDirEntry  = filePtr.GetStructure <StDirEntry>();

                //压栈;避免使用continue导致死循环以及冗余代码;
                void Push()
                {
                    if (file != null)
                    {
                        haveFileCollection.Children.Add(file);
                    }
                    filePtr = stDirEntry.Next;
                }

                if (stDirEntry.DirInfo == IntPtr.Zero)
                {
                    Push();
                    continue;
                }

                var stExtDirEntry = stDirEntry.DirInfo.GetStructure <StExt4DirEntry>();

                var stExtINodePtr = ExtX_Get_InodeInfo(partInfo.ExtUnmanagedManager.ExtManagerPtr, stExtDirEntry.inode);
                if (stExtINodePtr == IntPtr.Zero)
                {
                    LoggerService.WriteCallerLine($"{nameof(stExtINodePtr)} can't be nullptr.");
                    Push();
                    continue;
                }
                var stExtINode = stExtINodePtr.GetStructure <StExt4Inode>();

                var stBlockListPtr = ExtX_Get_BlockList(partInfo.ExtUnmanagedManager.ExtManagerPtr, stExtINodePtr);
                if (stBlockListPtr == IntPtr.Zero)
                {
                    //LoggerService.WriteCallerLine($"{nameof(stBlockListPtr)} can't be nullptr.");
                    Push();
                    continue;
                }

                var extFileInfo = new ExtFileInfo {
                    StDirEntry     = stDirEntry,
                    StExt4DirEntry = stExtDirEntry,
                    BlockListPtr   = stBlockListPtr,
                    StExt4Inode    = stExtINode
                };

                if (stExtDirEntry.file_type == Ext4FileType.Directory)
                {
                    var dir = FileFactory.CreateDirectory(Constants.DirectoryKey_Ext);

                    var dirStoken = dir.GetStoken(Constants.DirectoryKey_Ext);
                    dirStoken.TypeGuid = Constants.DirectoryType_Ext;

                    file        = dir;
                    fileStoken2 = dirStoken;

                    EditFileStoken2(fileStoken2, partInfo, extFileInfo);
                    //当目录名为".."或者"."时,跳过加载子文件;
                    //且所加载目录不能被删除;
                    if (stExtDirEntry._name[0] != '.' && !stDirEntry.bDel)
                    {
                        LoadDirectoryContent(dir, partInfo, ntfSzAct, isCancel);
                    }
                    else if (stExtDirEntry._name[1] == '.')
                    {
                        dirStoken.IsBack = true;
                    }
                    else
                    {
                        dirStoken.IsLocalBackUp = true;
                    }
                }
                else if (stExtDirEntry.file_type == Ext4FileType.RegularFile)
                {
                    var regFile       = FileFactory.CreateRegularFile(Constants.RegularFileKey_Ext);
                    var regFileStoken = regFile.GetStoken(Constants.RegularFileKey_Ext);

                    regFileStoken.TypeGuid = Constants.RegularFileType_Ext;

                    file        = regFile;
                    fileStoken2 = regFileStoken;

                    EditFileStoken2(fileStoken2, partInfo, extFileInfo);
                    ntfSzAct?.Invoke(fileStoken2.Size);
                }

                Push();

                if (isCancel?.Invoke() ?? false)
                {
                    return;
                }
            }
        }