From f7bd2e5aebec19f4c0cc48d0baf0543dbc2bbb1f Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 6 Feb 2026 12:58:54 +0000 Subject: [PATCH] [rbf] Implement directory operations. --- Aaru.Filesystems/RBF/Dir.cs | 159 ++++++++++++++++++++++++++ Aaru.Filesystems/RBF/Unimplemented.cs | 9 -- 2 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 Aaru.Filesystems/RBF/Dir.cs diff --git a/Aaru.Filesystems/RBF/Dir.cs b/Aaru.Filesystems/RBF/Dir.cs new file mode 100644 index 000000000..f9082d50d --- /dev/null +++ b/Aaru.Filesystems/RBF/Dir.cs @@ -0,0 +1,159 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Dir.cs +// Author(s) : Natalia Portillo +// +// Component : Random Block File filesystem plugin +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2026 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using Aaru.CommonTypes.Enums; +using Aaru.CommonTypes.Interfaces; + +namespace Aaru.Filesystems; + +/// +public sealed partial class RBF +{ + /// + public ErrorNumber OpenDir(string path, out IDirNode node) + { + node = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + // Normalize the path + string normalizedPath = path ?? "/"; + + if(normalizedPath == "" || normalizedPath == ".") normalizedPath = "/"; + + // Root directory + if(normalizedPath == "/") + { + node = new RbfDirNode + { + Path = "/", + Position = 0, + DirectoryFdLsn = _rootDirLsn, + Contents = _rootDirectoryCache.Keys.ToArray() + }; + + return ErrorNumber.NoError; + } + + // Remove leading slash and split path + string pathWithoutLeadingSlash = normalizedPath.StartsWith("/", StringComparison.Ordinal) + ? normalizedPath[1..] + : normalizedPath; + + string[] pathComponents = pathWithoutLeadingSlash.Split('/', StringSplitOptions.RemoveEmptyEntries); + + if(pathComponents.Length == 0) return ErrorNumber.InvalidArgument; + + // Start traversal from root directory cache + Dictionary currentDirectory = _rootDirectoryCache; + CachedDirectoryEntry targetEntry = null; + + // Traverse all path components + for(var i = 0; i < pathComponents.Length; i++) + { + string component = pathComponents[i]; + + // Skip . and .. + if(component == "." || component == "..") continue; + + // Find the component in current directory + if(!currentDirectory.TryGetValue(component, out CachedDirectoryEntry entry)) return ErrorNumber.NoSuchFile; + + // If this is the last component, we found our target + if(i == pathComponents.Length - 1) + { + targetEntry = entry; + + break; + } + + // Not the last component - must be a directory to continue traversal + if(!entry.IsDirectory) return ErrorNumber.NotDirectory; + + // Read the subdirectory contents + ErrorNumber errno = ReadDirectoryContents(entry.Fd, out Dictionary subDir); + + if(errno != ErrorNumber.NoError) return errno; + + currentDirectory = subDir; + } + + if(targetEntry == null) return ErrorNumber.NoSuchFile; + + // Verify the target is a directory + if(!targetEntry.IsDirectory) return ErrorNumber.NotDirectory; + + // Read the target directory contents + ErrorNumber readError = ReadDirectoryContents(targetEntry.Fd, + out Dictionary targetContents); + + if(readError != ErrorNumber.NoError) return readError; + + node = new RbfDirNode + { + Path = normalizedPath, + Position = 0, + DirectoryFdLsn = targetEntry.FdLsn, + Contents = targetContents.Keys.ToArray() + }; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber CloseDir(IDirNode node) + { + if(node is not RbfDirNode rbfNode) return ErrorNumber.InvalidArgument; + + rbfNode.Position = -1; + rbfNode.Contents = null; + + return ErrorNumber.NoError; + } + + /// + public ErrorNumber ReadDir(IDirNode node, out string filename) + { + filename = null; + + if(!_mounted) return ErrorNumber.AccessDenied; + + if(node is not RbfDirNode rbfNode) return ErrorNumber.InvalidArgument; + + if(rbfNode.Position < 0) return ErrorNumber.InvalidArgument; + + if(rbfNode.Contents == null || rbfNode.Position >= rbfNode.Contents.Length) return ErrorNumber.NoError; + + filename = rbfNode.Contents[rbfNode.Position++]; + + return ErrorNumber.NoError; + } +} \ No newline at end of file diff --git a/Aaru.Filesystems/RBF/Unimplemented.cs b/Aaru.Filesystems/RBF/Unimplemented.cs index 8875a59ec..33ed8e9cb 100644 --- a/Aaru.Filesystems/RBF/Unimplemented.cs +++ b/Aaru.Filesystems/RBF/Unimplemented.cs @@ -48,13 +48,4 @@ public sealed partial class RBF /// public ErrorNumber ReadFile(IFileNode node, long length, byte[] buffer, out long read) => throw new NotImplementedException(); - - /// - public ErrorNumber OpenDir(string path, out IDirNode node) => throw new NotImplementedException(); - - /// - public ErrorNumber CloseDir(IDirNode node) => throw new NotImplementedException(); - - /// - public ErrorNumber ReadDir(IDirNode node, out string filename) => throw new NotImplementedException(); } \ No newline at end of file