public async Task <ParsedPath[]> GetPhysicalFileStateInternal(string logicalFilePath, CancellationToken cancel)
    {
        List <ParsedPath> ret = new List <ParsedPath>();

        ParsedPath parsed = new ParsedPath(this, logicalFilePath, 0);

        FileSystemEntity[] dirEntities = await UnderlayFileSystem.EnumDirectoryAsync(parsed.DirectoryPath, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel);

        var relatedFiles = dirEntities.Where(x => x.IsDirectory == false);

        foreach (var f in relatedFiles)
        {
            if (f.Name.StartsWith(parsed.OriginalFileNameWithoutExtension, PathParser.PathStringComparison))
            {
                try
                {
                    ParsedPath parsedForFile = new ParsedPath(this, f.FullPath, f);
                    if (parsed.LogicalFilePath._IsSame(parsedForFile.LogicalFilePath, PathParser.PathStringComparison))
                    {
                        ret.Add(parsedForFile);
                    }
                }
                catch { }
            }
        }

        ret.Sort((x, y) => x.FileNumber.CompareTo(y.FileNumber));

        return(ret.ToArray());
    }
        protected override async Task <FileMetadata> GetFileMetadataImplAsync(string path, FileMetadataGetFlags flags = FileMetadataGetFlags.DefaultAll, CancellationToken cancel = default)
        {
            FileMetadata physicalMetadata = await UnderlayFileSystem.GetFileMetadataAsync(path, flags, cancel);

            try
            {
                long headerOffset = 0;
                long physicalSize = physicalMetadata.Size;

                using (FileObject physicalFile = await UnderlayFileSystem.OpenAsync(path))
                {
                    byte[]        bomRead = new byte[3];
                    Memory <byte> tmp     = new byte[3];
                    if (await physicalFile.ReadRandomAsync(0, tmp, cancel) == tmp.Length)
                    {
                        if (tmp.Span.SequenceEqual(Str.BOM_UTF_8.Span))
                        {
                            headerOffset = 3;
                        }
                    }

                    physicalSize = await physicalFile.GetFileSizeAsync(true, cancel) - headerOffset;

                    if (physicalSize >= 0)
                    {
                        physicalMetadata.Size = physicalSize;
                    }
                }
            }
            catch { }

            return(physicalMetadata);
        }
    protected override async Task <FileObject> CreateFileImplAsync(FileParameters option, CancellationToken cancel = default)
    {
        string fileName = this.PathParser.GetFileName(option.Path);

        if (fileName.IndexOf(Params.SplitStr) != -1)
        {
            throw new ApplicationException($"The original filename '{fileName}' contains '{Params.SplitStr}'.");
        }

        await using (CreatePerTaskCancellationToken(out CancellationToken operationCancel, cancel))
        {
            using (await AsyncLockObj.LockWithAwait(operationCancel))
            {
                cancel.ThrowIfCancellationRequested();

                bool isSimplePhysicalFileExists = await UnderlayFileSystem.IsFileExistsAsync(option.Path);

                if (isSimplePhysicalFileExists)
                {
                    // If there is a simple physical file, open it.
                    return(await UnderlayFileSystem.CreateFileAsync(option, cancel));
                }

                ParsedPath[] relatedFiles = await GetPhysicalFileStateInternal(option.Path, operationCancel);

                return(await LargeFileObject.CreateFileAsync(this, option, relatedFiles, operationCancel));
            }
        }
    }
    protected override async Task SetFileMetadataImplAsync(string path, FileMetadata metadata, CancellationToken cancel = default)
    {
        // Try physical file first
        try
        {
            if (await UnderlayFileSystem.IsFileExistsAsync(path, cancel))
            {
                await UnderlayFileSystem.SetFileMetadataAsync(path, metadata, cancel);

                return;
            }
        }
        catch { }
        LargeFileSystem.ParsedPath[] physicalFiles = await GetPhysicalFileStateInternal(path, cancel);

        if (physicalFiles._IsEmpty())
        {
            // File not found
            throw new IOException($"The file '{path}' not found.");
        }

        Exception?exception = null;

        foreach (var file in physicalFiles.OrderBy(x => x.PhysicalFilePath, PathParser.PathStringComparer))
        {
            cancel.ThrowIfCancellationRequested();

            try
            {
                await UnderlayFileSystem.SetFileMetadataAsync(file.PhysicalFilePath, metadata, cancel);
            }
            catch (Exception ex)
            {
                if (exception == null)
                {
                    exception = ex;
                }
            }
        }

        if (exception != null)
        {
            throw exception;
        }
    }
    protected override async Task <bool> IsFileExistsImplAsync(string path, CancellationToken cancel = default)
    {
        // Try physical file first
        try
        {
            if (await UnderlayFileSystem.IsFileExistsAsync(path, cancel))
            {
                return(true);
            }
        }
        catch { }

        LargeFileSystem.ParsedPath[] physicalFiles = await GetPhysicalFileStateInternal(path, cancel);

        var lastFileParsed = physicalFiles.OrderBy(x => x.FileNumber).LastOrDefault();

        return(lastFileParsed != null);
    }
Example #6
0
    protected virtual async Task <ViewFileObjectInitUnderlayFileResultParam> CreateUnderlayFileImplAsync(FileParameters option, CancellationToken cancel = default)
    {
        FileObject obj = await UnderlayFileSystem.CreateFileAsync(option, cancel);

        try
        {
            ViewFileObjectInitUnderlayFileResultParam result = new ViewFileObjectInitUnderlayFileResultParam(
                obj,
                obj.FileParams.Flags.Bit(FileFlags.RandomAccessOnly) ? 0 : obj.Position,
                obj.Size);

            return(result);
        }
        catch
        {
            obj._DisposeSafe();
            throw;
        }
    }
    protected override async Task <FileMetadata> GetFileMetadataImplAsync(string path, FileMetadataGetFlags flags = FileMetadataGetFlags.DefaultAll, CancellationToken cancel = default)
    {
        // Try physical file first
        try
        {
            return(await UnderlayFileSystem.GetFileMetadataAsync(path, flags, cancel));
        }
        catch { }

        LargeFileSystem.ParsedPath[] physicalFiles = await GetPhysicalFileStateInternal(path, cancel);

        var lastFileParsed = physicalFiles.OrderBy(x => x.FileNumber).LastOrDefault();

        if (lastFileParsed == null)
        {
            // File not found
            throw new IOException($"The file '{path}' not found.");
        }
        else
        {
            // Large file exists
            checked
            {
                FileMetadata ret = await UnderlayFileSystem.GetFileMetadataAsync(lastFileParsed.PhysicalFilePath, flags | FileMetadataGetFlags.NoSecurity | FileMetadataGetFlags.NoAlternateStream, cancel);

                long sizeOfLastFile = ret.Size;
                sizeOfLastFile = Math.Min(sizeOfLastFile, Params.MaxSinglePhysicalFileSize);

                long currentFileSize = lastFileParsed.FileNumber * Params.MaxSinglePhysicalFileSize + sizeOfLastFile;

                ret.Size           = currentFileSize;
                ret.PhysicalSize   = physicalFiles.Sum(x => x.PhysicalEntity !.PhysicalSize);
                ret.CreationTime   = physicalFiles.Min(x => x.PhysicalEntity !.CreationTime);
                ret.LastWriteTime  = physicalFiles.Max(x => x.PhysicalEntity !.LastWriteTime);
                ret.LastAccessTime = physicalFiles.Max(x => x.PhysicalEntity !.LastAccessTime);

                return(ret);
            }
        }
    }
 protected override Task DeleteDirectoryImplAsync(string directoryPath, bool recursive, CancellationToken cancel = default)
 => UnderlayFileSystem.DeleteDirectoryAsync(directoryPath, recursive);
 protected override Task CreateDirectoryImplAsync(string directoryPath, FileFlags flags = FileFlags.None, CancellationToken cancel = default)
 => UnderlayFileSystem.CreateDirectoryAsync(directoryPath, flags, cancel);
    protected override async Task <FileSystemEntity[]> EnumDirectoryImplAsync(string directoryPath, EnumDirectoryFlags flags, CancellationToken cancel = default)
    {
        checked
        {
            FileSystemEntity[] dirEntities = await UnderlayFileSystem.EnumDirectoryAsync(directoryPath, false, flags, cancel);

            var relatedFiles = dirEntities.Where(x => x.IsDirectory == false).Where(x => x.Name.IndexOf(Params.SplitStr) != -1);

            var sortedRelatedFiles = relatedFiles.ToList();
            sortedRelatedFiles.Sort((x, y) => x.Name._Cmp(y.Name, PathParser.PathStringComparison));
            sortedRelatedFiles.Reverse();

            Dictionary <string, FileSystemEntity> parsedFileDictionaly = new Dictionary <string, FileSystemEntity>(PathParser.PathStringComparer);

            var normalFiles       = dirEntities.Where(x => x.IsDirectory == false).Where(x => x.Name.IndexOf(Params.SplitStr) == -1);
            var normalFileHashSet = new HashSet <string>(normalFiles.Select(x => x.Name), PathParser.PathStringComparer);

            foreach (FileSystemEntity f in sortedRelatedFiles)
            {
                try
                {
                    // Split files
                    ParsedPath parsed = new ParsedPath(this, f.FullPath, f);

                    if (parsedFileDictionaly.ContainsKey(parsed.LogicalFileName) == false)
                    {
                        FileSystemEntity newFileEntity = new FileSystemEntity(
                            fullPath: parsed.LogicalFilePath,
                            name: PathParser.GetFileName(parsed.LogicalFileName),
                            size: f.Size + parsed.FileNumber * Params.MaxSinglePhysicalFileSize,
                            physicalSize: f.PhysicalSize,
                            attributes: f.Attributes,
                            creationTime: f.CreationTime,
                            lastWriteTime: f.LastWriteTime,
                            lastAccessTime: f.LastAccessTime
                            );

                        parsedFileDictionaly.Add(parsed.LogicalFileName, newFileEntity);
                    }
                    else
                    {
                        var fileEntity = parsedFileDictionaly[parsed.LogicalFileName];

                        fileEntity.PhysicalSize += f.PhysicalSize;

                        if (fileEntity.CreationTime > f.CreationTime)
                        {
                            fileEntity.CreationTime = f.CreationTime;
                        }
                        if (fileEntity.LastWriteTime < f.LastWriteTime)
                        {
                            fileEntity.LastWriteTime = f.LastWriteTime;
                        }
                        if (fileEntity.LastAccessTime < f.LastAccessTime)
                        {
                            fileEntity.LastAccessTime = f.LastAccessTime;
                        }
                    }
                }
                catch { }
            }

            var logicalFiles = parsedFileDictionaly.Values.Where(x => normalFileHashSet.Contains(x.Name) == false);

            var retList = dirEntities.Where(x => x.IsDirectory)
                          .Concat(logicalFiles)
                          .Concat(normalFiles)
                          .OrderByDescending(x => x.IsDirectory)
                          .ThenBy(x => x.Name);

            return(retList._ToArrayList());
        }
    }
 protected override IFileProvider CreateFileProviderForWatchImpl(string root) => UnderlayFileSystem._CreateFileProviderForWatchInternal(EnsureInternal.Yes, root);
 protected override Task <FileMetadata> GetDirectoryMetadataImplAsync(string path, FileMetadataGetFlags flags = FileMetadataGetFlags.DefaultAll, CancellationToken cancel = default)
 => UnderlayFileSystem.GetDirectoryMetadataAsync(path, flags | FileMetadataGetFlags.NoAlternateStream | FileMetadataGetFlags.NoSecurity, cancel);
 protected override Task SetDirectoryMetadataImplAsync(string path, FileMetadata metadata, CancellationToken cancel = default)
 => UnderlayFileSystem.SetDirectoryMetadataAsync(path, metadata, cancel);
    protected override async Task DeleteFileImplAsync(string path, FileFlags flags = FileFlags.None, CancellationToken cancel = default)
    {
        // Try physical file first
        try
        {
            if (await UnderlayFileSystem.IsFileExistsAsync(path, cancel))
            {
                await UnderlayFileSystem.DeleteFileAsync(path, flags, cancel);

                return;
            }
        }
        catch { }

        LargeFileSystem.ParsedPath[] physicalFiles = await GetPhysicalFileStateInternal(path, cancel);

        if (physicalFiles._IsEmpty())
        {
            // File not found
            return;
        }

        await UnderlayFileSystemPoolForWrite.EnumAndCloseHandlesAsync((key, file) =>
        {
            if (physicalFiles.Where(x => x.PhysicalFilePath._IsSame(file.FileParams.Path, PathParser.PathStringComparison)).Any())
            {
                return(true);
            }
            return(false);
        },
                                                                      () =>
        {
            foreach (LargeFileSystem.ParsedPath deleteFile in physicalFiles.OrderByDescending(x => x.PhysicalFilePath))
            {
                UnderlayFileSystem.DeleteFile(deleteFile.PhysicalFilePath, FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel);
            }
        },
                                                                      (x, y) =>
        {
            return(-(x.FileParams.Path.CompareTo(y.FileParams.Path)));
        },
                                                                      cancel);

        await UnderlayFileSystemPoolForRead.EnumAndCloseHandlesAsync((key, file) =>
        {
            if (physicalFiles.Where(x => x.PhysicalFilePath._IsSame(file.FileParams.Path, PathParser.PathStringComparison)).Any())
            {
                return(true);
            }
            return(false);
        },
                                                                     () =>
        {
            foreach (LargeFileSystem.ParsedPath deleteFile in physicalFiles.OrderByDescending(x => x.PhysicalFilePath))
            {
                UnderlayFileSystem.DeleteFile(deleteFile.PhysicalFilePath, FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel);
            }
        },
                                                                     (x, y) =>
        {
            return(-(x.FileParams.Path.CompareTo(y.FileParams.Path)));
        },
                                                                     cancel);
    }
 protected override Task <bool> IsDirectoryExistsImplAsync(string path, CancellationToken cancel = default)
 => UnderlayFileSystem.IsDirectoryExistsAsync(path, cancel);