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); }
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);