public override async ValueTask <FileHandle> CreateDirectory(FileHandle parentFileHandle, string name) { var parentLocalFileHandle = new LocalFileHandle(parentFileHandle); var stats = StatRealPath(GetRealPath(parentLocalFileHandle.Path)); if (!parentLocalFileHandle.IsSameFile(stats)) { throw new FileNotFoundException(parentFileHandle); } if (!stats.Type.HasFlag(FileType.Directory)) { throw new FileNotADirectoryException(parentFileHandle); } var targetPath = PathLib.Join(parentLocalFileHandle.Path, name); var targetRealPath = GetRealPath(targetPath); var fileType = GetFileType(targetRealPath); if (fileType != null) { throw new FileExistsException($"The file '{targetPath}' existed."); } Directory.CreateDirectory(targetRealPath); var targetStat = StatRealPath(targetRealPath); var targetFileHandle = new LocalFileHandle(targetPath, targetStat).FileHandle; await IndexFile(targetPath, targetFileHandle, targetStat); return(targetFileHandle); }
public void JoinTest() { var joinTests = new Dictionary <string[], string> { { new[] { ".", "x/b", "..", "/b/c.js" }, "x/b/c.js" }, { Array.Empty <string>(), "." }, { new[] { "/.", "x/b", "..", "/b/c.js" }, "/x/b/c.js" }, { new[] { "/foo", "../../../bar" }, "/bar" }, { new[] { "foo", "../../../bar" }, "../../bar" }, { new[] { "foo/", "../../../bar" }, "../../bar" }, { new[] { "foo/x", "../../../bar" }, "../bar" }, { new[] { "foo/x", "./bar" }, "foo/x/bar" }, { new[] { "foo/x/", "./bar" }, "foo/x/bar" }, { new[] { "foo/x/", ".", "bar" }, "foo/x/bar" }, { new[] { "./" }, "./" }, { new[] { ".", "./" }, "./" }, { new[] { ".", ".", "." }, "." }, { new[] { ".", "./", "." }, "." }, { new[] { ".", "/./", "." }, "." }, { new[] { ".", "/////./", "." }, "." }, { new[] { "." }, "." }, { new[] { "", "." }, "." }, { new[] { "", "foo" }, "foo" }, { new[] { "foo", "/bar" }, "foo/bar" }, { new[] { "", "/foo" }, "/foo" }, { new[] { "", "", "/foo" }, "/foo" }, { new[] { "", "", "foo" }, "foo" }, { new[] { "foo", "" }, "foo" }, { new[] { "foo/", "" }, "foo/" }, { new[] { "foo", "", "/bar" }, "foo/bar" }, { new[] { "./", "..", "/foo" }, "../foo" }, { new[] { "./", "..", "..", "/foo" }, "../../foo" }, { new[] { ".", "..", "..", "/foo" }, "../../foo" }, { new[] { "", "..", "..", "/foo" }, "../../foo" }, { new[] { "/" }, "/" }, { new[] { "/", "." }, "/" }, { new[] { "/", ".." }, "/" }, { new[] { "/", "..", ".." }, "/" }, { new[] { "" }, "." }, { new[] { "", "" }, "." }, { new[] { " /foo" }, " /foo" }, { new[] { " ", "foo" }, " /foo" }, { new[] { " ", "." }, " " }, { new[] { " ", "/" }, " /" }, { new[] { " ", "" }, " " }, { new[] { "/", "foo" }, "/foo" }, { new[] { "/", "/foo" }, "/foo" }, { new[] { "/", "//foo" }, "/foo" }, { new[] { "/", "", "/foo" }, "/foo" }, { new[] { "", "/", "foo" }, "/foo" }, { new[] { "", "/", "/foo" }, "/foo" } }; foreach (var(test, expected) in joinTests) { Assert.AreEqual(expected, PathLib.Join(test)); } }
public override async ValueTask Delete(FileHandle fileHandle, FileHandle parentFileHandle, string name, bool recursive) { var localFileHandle = new LocalFileHandle(fileHandle); var parentLocalFileHandle = new LocalFileHandle(parentFileHandle); // check if (localFileHandle.Path != PathLib.Join(parentLocalFileHandle.Path, name)) { throw new FileNotFoundException("File handles are inconsistent."); } var stats = StatRealPath(GetRealPath(localFileHandle.Path)); var parentStats = StatRealPath(GetRealPath(parentLocalFileHandle.Path)); if (!localFileHandle.IsSameFile(stats)) { throw new FileNotFoundException(fileHandle); } if (!parentLocalFileHandle.IsSameFile(parentStats)) { throw new FileNotFoundException(parentFileHandle); } var realPath = GetRealPath(localFileHandle.Path); if (stats.Type.HasFlag(FileType.Directory)) { if (recursive) { Directory.Delete(realPath, true); } else { throw new FileIsADirectoryException(fileHandle); } } else { File.Delete(realPath); } await IndexDeletedFile(localFileHandle.Path, fileHandle); }
public override async ValueTask <IEnumerable <Dirent> > ReadDirectory(FileHandle fileHandle) { var localFileHandle = new LocalFileHandle(fileHandle); var realPath = GetRealPath(localFileHandle.Path); var directoryInfo = new DirectoryInfo(realPath); if (!directoryInfo.Exists) { var fileType = GetFileType(realPath); if (fileType != null && !fileType.Value.HasFlag(FileType.Directory)) { throw new FileNotADirectoryException(fileHandle); } throw new FileNotFoundException(fileHandle); } var stats = GetFileStatFromFileSystemInfo(directoryInfo); if (!localFileHandle.IsSameFile(stats)) { throw new FileNotFoundException(fileHandle); } var result = directoryInfo.EnumerateFileSystemInfos().Select(info => { var entryLocalFileHandle = new LocalFileHandle( PathLib.Join(localFileHandle.Path, info.Name), GetFileStatFromFileSystemInfo(info)); return(new Dirent( info.Name, entryLocalFileHandle.FileHandle, GetFileStatFromFileSystemInfo(info))); }).ToImmutableArray(); await IndexDirectory(localFileHandle.Path, fileHandle, result); return(result); }
public override async ValueTask <FileHandle> CreateFile(FileHandle parentFileHandle, string name, ReadOnlyMemory <byte> content) { var parentLocalFileHandle = new LocalFileHandle(parentFileHandle); var parentFilePath = parentLocalFileHandle.Path; var filePath = PathLib.Join(parentFilePath, name); var parentStats = StatRealPath(GetRealPath(parentFilePath)); if (!parentLocalFileHandle.IsSameFile(parentStats)) { throw new FileNotFoundException(parentFileHandle); } if (!parentStats.Type.HasFlag(FileType.Directory)) { throw new FileNotADirectoryException(parentFileHandle); } var realPath = GetRealPath(filePath); if (GetFileType(realPath) != null) { throw new FileExistsException($"The file '{filePath}' existed."); } await using var fileStream = File.OpenWrite(realPath); await fileStream.WriteAsync(content); await fileStream.FlushAsync(); var newStats = StatRealPath(realPath); var newFileHandle = new LocalFileHandle(filePath, newStats).FileHandle; await IndexFile(parentFilePath, newFileHandle, newStats); return(newFileHandle); }
/// <summary> /// Create indexes of the contents in the directory. /// </summary> /// <param name="path">The path of the directory.</param> /// <param name="contents">The contents in the directory.</param> private async ValueTask IndexDirectory( IDbTransaction transaction, string path, IEnumerable <Dirent> contents, FileChangeEventBuilder eventBuilder) { var directoryId = await CreateDirectory(transaction, path, eventBuilder); var oldContents = (await _databaseTable.SelectByParentAsync(transaction, directoryId)).ToDictionary(content => content.Path); var newContents = contents.Select( content => new { Path = PathLib.Join(path, content.Name), Parent = directoryId, IsDirectory = content.Stats.Type.HasFlag(FileType.Directory), IdentifierTag = content.FileHandle.Identifier, content.FileHandle, FileStats = content.Stats }) .ToDictionary(content => content.Path); var addedContents = newContents.Keys.Except(oldContents.Keys).Select(key => newContents[key]).ToList(); var removedContents = oldContents.Keys.Except(newContents.Keys).Select(key => oldContents[key]).ToList(); var reservedContents = oldContents.Keys.Intersect(newContents.Keys).Select( key => new { oldContents[key].Path, oldFile = oldContents[key], newFile = newContents[key] }); var updatedTagContents = new List <(long Id, string Path, FileHandle FileHandle, FileStats FileStats, bool IsNew)>(); foreach (var reservedContent in reservedContents) { var oldFile = reservedContent.oldFile; var newFile = reservedContent.newFile; if (oldFile.IsDirectory != newFile.IsDirectory) { removedContents.Add(oldFile); addedContents.Add(newFile); } else if (oldFile.IdentifierTag == null) { updatedTagContents.Add( (oldFile.Id, newFile.Path, newFile.FileHandle, newFile.FileStats, true)); } else if (oldFile.IdentifierTag != newFile.IdentifierTag) { removedContents.Add(oldFile); addedContents.Add(newFile); } else if (oldFile.ContentTag != newFile.FileStats.Hash.ContentTag) { updatedTagContents.Add((oldFile.Id, newFile.Path, newFile.FileHandle, newFile.FileStats, false)); } } foreach (var removed in removedContents) { await Delete(transaction, removed, eventBuilder); } foreach (var added in addedContents) { await _databaseTable.InsertAsync( transaction, added.Path, directoryId, added.IsDirectory, added.FileHandle.Identifier, added.FileStats.Hash.ContentTag); eventBuilder.Created(added.FileHandle); } foreach (var updatedTagContent in updatedTagContents) { if (updatedTagContent.IsNew) { await _databaseTable.UpdateIdentifierTagByIdAsync( transaction, updatedTagContent.Id, updatedTagContent.FileHandle.Identifier, updatedTagContent.FileStats.Hash.ContentTag); eventBuilder.Created(updatedTagContent.FileHandle); } else { await _databaseTable.UpdateStatsByIdAsync( transaction, updatedTagContent.Id, updatedTagContent.FileStats.Hash.ContentTag); await _databaseTable.DeletePropertyOnFileUpdated(transaction, updatedTagContent.Id); eventBuilder.Changed(updatedTagContent.FileHandle); } } }
private static async IAsyncEnumerable <FileSystemWalkerEntry> EnumerateAllFiles( ISingletonFileSystem singletonFileSystem, FileHandle rootFileHandle) { var directoryWalker = new FileSystemDirectoryWalker(singletonFileSystem, rootFileHandle); await foreach (var directory in directoryWalker) { foreach (var entries in directory.Entries) { yield return(new FileSystemWalkerEntry(entries.FileHandle, entries.Stats, PathLib.Join(directory.Path, entries.Name))); } } }
public override async ValueTask <FileHandle> Rename( FileHandle fileHandle, FileHandle oldParentFileHandle, string oldName, FileHandle newParentFileHandle, string newName) { var localFileHandle = new LocalFileHandle(fileHandle); var oldParentLocalFileHandle = new LocalFileHandle(oldParentFileHandle); var newParentLocalFileHandle = new LocalFileHandle(newParentFileHandle); // check if (localFileHandle.Path != PathLib.Join(oldParentLocalFileHandle.Path, oldName)) { throw new FileNotFoundException("File handles are inconsistent."); } var oldRealPath = GetRealPath(localFileHandle.Path); var oldFileStats = StatRealPath(oldRealPath); var oldParentStats = StatRealPath(GetRealPath(oldParentLocalFileHandle.Path)); var newParentStats = StatRealPath(GetRealPath(newParentLocalFileHandle.Path)); if (!localFileHandle.IsSameFile(oldFileStats)) { throw new FileNotFoundException(fileHandle); } if (!oldParentLocalFileHandle.IsSameFile(oldParentStats)) { throw new FileNotFoundException(oldParentFileHandle); } if (!newParentLocalFileHandle.IsSameFile(newParentStats)) { throw new FileNotFoundException(newParentFileHandle); } if (!newParentStats.Type.HasFlag(FileType.Directory)) { throw new FileNotADirectoryException(newParentFileHandle); } var newPath = PathLib.Join(newParentLocalFileHandle.Path, newName); var newRealPath = GetRealPath(newPath); if (GetFileType(newRealPath) != null) { throw new FileExistsException($"The file '{newPath}' existed."); } if (oldFileStats.Type.HasFlag(FileType.Directory)) { Directory.Move(oldRealPath, newRealPath); } else { File.Move(oldRealPath, newRealPath, false); } var newFileStats = StatRealPath(newRealPath); await IndexDeletedFile(localFileHandle.Path, fileHandle); var newFileHandle = new LocalFileHandle(newPath, newFileStats).FileHandle; await IndexFile(newPath, new LocalFileHandle(newPath, newFileStats).FileHandle, newFileStats); return(newFileHandle); }