public void CreateDir(ResourcePath path)
        {
            if (!path.IsRooted)
            {
                throw new ArgumentException("Path must be rooted", nameof(path));
            }

            path = path.Clean();

            var directory = _rootDirectoryNode;

            foreach (var segment in path.EnumerateSegments())
            {
                if (directory.Children.TryGetValue(segment, out var child))
                {
                    if (!(child is DirectoryNode childDir))
                    {
                        throw new ArgumentException("A file already exists at that location.");
                    }

                    directory = childDir;
                    continue;
                }

                var newDir = new DirectoryNode();

                directory.Children.Add(segment, newDir);
            }
        }
        private static string GetFullPath(string root, ResourcePath path)
        {
            var relPath = path.Clean().ToRelativeSystemPath();

            if (relPath.Contains("\\..") || relPath.Contains("/.."))
            {
                // Hard cap on any exploit smuggling a .. in there.
                // Since that could allow leaving sandbox.
                throw new InvalidOperationException("This branch should never be reached.");
            }

            return(Path.GetFullPath(Path.Combine(root, relPath)));
        }
        public void Delete(ResourcePath path)
        {
            if (!path.IsRooted)
            {
                throw new ArgumentException("Path must be rooted", nameof(path));
            }

            path = path.Clean();

            var pathParent = path.Directory;

            if (!TryGetNodeAt(pathParent, out var parent) || !(parent is DirectoryNode directory))
            {
                return;
            }

            directory.Children.Remove(path.Filename);
        }
        private bool TryGetNodeAt(ResourcePath path, out INode node)
        {
            if (!path.IsRooted)
            {
                throw new ArgumentException("Path must be rooted", nameof(path));
            }

            path = path.Clean();

            if (path == ResourcePath.Root)
            {
                node = _rootDirectoryNode;
                return(true);
            }

            var directory = _rootDirectoryNode;
            var segments  = path.EnumerateSegments().ToArray();

            for (var i = 0; i < segments.Length; i++)
            {
                var segment = segments[i];
                if (!directory.Children.TryGetValue(segment, out var child))
                {
                    node = default;
                    return(false);
                }

                if (i == segments.Length - 1)
                {
                    node = child;
                    return(true);
                }

                directory = (DirectoryNode)child;
            }

            throw new InvalidOperationException("Unreachable.");
        }
Beispiel #5
0
        private static string GetFullPath(string root, ResourcePath path)
        {
            var relPath = path.Clean().ToRelativePath().ToString();

            return(Path.GetFullPath(Path.Combine(root, relPath)));
        }
        public Stream Open(ResourcePath path, FileMode fileMode)
        {
            if (!path.IsRooted)
            {
                throw new ArgumentException("Path must be rooted", nameof(path));
            }

            path = path.Clean();

            var parentPath = path.Directory;

            if (!TryGetNodeAt(parentPath, out var parent) || !(parent is DirectoryNode parentDir))
            {
                throw new ArgumentException("Parent directory does not exist.");
            }

            var fileName = path.Filename;

            if (parentDir.Children.TryGetValue(fileName, out var maybeFileNode) && maybeFileNode is DirectoryNode)
            {
                throw new ArgumentException("There is a directory at that location.");
            }

            var fileNode = (FileNode)maybeFileNode;

            switch (fileMode)
            {
            case FileMode.Append:
            {
                if (fileNode == null)
                {
                    fileNode = new FileNode();
                    parentDir.Children.Add(fileName, fileNode);
                }

                return(new VirtualFileStream(fileNode.Contents, false, true, fileNode.Contents.Length));
            }

            case FileMode.Create:
            {
                if (fileNode == null)
                {
                    fileNode = new FileNode();
                    parentDir.Children.Add(fileName, fileNode);
                }
                else
                {
                    // Clear contents if it already exists.
                    fileNode.Contents.SetLength(0);
                }

                return(new VirtualFileStream(fileNode.Contents, true, true, 0));
            }

            case FileMode.CreateNew:
            {
                if (fileNode != null)
                {
                    throw new IOException("File already exists.");
                }

                fileNode = new FileNode();
                parentDir.Children.Add(fileName, fileNode);

                return(new VirtualFileStream(fileNode.Contents, true, true, 0));
            }

            case FileMode.Open:
            {
                if (fileNode == null)
                {
                    throw new FileNotFoundException();
                }

                return(new VirtualFileStream(fileNode.Contents, true, true, 0));
            }

            case FileMode.OpenOrCreate:
            {
                if (fileNode == null)
                {
                    fileNode = new FileNode();
                    parentDir.Children.Add(fileName, fileNode);
                }

                return(new VirtualFileStream(fileNode.Contents, true, true, 0));
            }

            case FileMode.Truncate:
            {
                if (fileNode == null)
                {
                    throw new FileNotFoundException();
                }

                fileNode.Contents.SetLength(0);

                return(new VirtualFileStream(fileNode.Contents, true, true, 0));
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(fileMode), fileMode, null);
            }
        }