In-Memory File System: Add cd and Relative Path Support

Read the full interview experience this question came from →

Quick Overview

A multi-part coding exercise that builds an in-memory file system with directories, files and listings over absolute paths, then adds a cd command and relative path support to every operation. It tests tree data structures, path normalization with dot and dot-dot components, consistent error handling and safely refactoring earlier code.

In-Memory File System: Add cd and Relative Path Support

Company: Perplexity

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

Implement an in-memory file system as a class, in stages. The early stages build a tree of directories and files addressed by absolute paths. The final stage adds a current working directory with a `cd` command and requires every operation to accept relative paths as well. That final stage is where the difficulty lies: path handling written for absolute paths has to change without breaking what already works, and relative-path bugs are easy to introduce. The earlier stages are not specified in detail here, so Part 1 states an assumed baseline API. If your interviewer gives a different one, keep its semantics and apply Part 2 to it. Part 2 is the extension the question builds toward. ### Clarifying Questions - Are file contents plain strings, and does writing to an existing file overwrite it or append to it? - Should `ls` return names in sorted order, and what should it return when the path is a file? - How should errors be reported: exceptions, return values, or silently ignored? - Can paths contain repeated slashes or a trailing slash, or are inputs always well formed? ### Part 1 — Baseline file system over absolute paths Implement this API. Every path is absolute: it starts with `/`, and `/` alone is the root. ```python class FileSystem: def mkdir(self, path: str) -> None: ... def write_file(self, path: str, content: str) -> None: ... def read_file(self, path: str) -> str: ... def ls(self, path: str) -> list[str]: ... ``` - `mkdir` creates the directory and any missing parent directories. It is an error if some component of the path is an existing file. - `write_file` creates the file or overwrites its content. Its parent directory must already exist, and the path must not name a directory. - `read_file` returns a file's content; the path must name an existing file. - `ls` returns the names of a directory's entries in sorted order, or a one-element list with the file's own name when the path names a file. ```hint One tree, one walk Decide how directories and files differ in your representation, and write the walk from the root to a node once, so that every method reuses it instead of splitting paths itself. ``` #### What This Part Should Cover - A tree in which directories map names to children and files hold content - A single traversal helper shared by all methods - Defined behavior for missing paths, a file used as a directory, and the root itself ### Part 2 — Add `cd` and relative paths Add `cd(path)`, which changes the current working directory, and a `pwd()` helper that returns the current directory as an absolute path, so the behavior can be tested. The file system starts in `/`. From now on every method, including `cd` itself, must accept both absolute paths and relative paths such as `docs/a.txt`, `./docs` or `../shared/b.txt`, which are resolved against the current directory. ```hint Count the places that read a path Before writing `cd`, find every place in your Part 1 code that interprets a path string. Relative paths become a small change only if there is exactly one such place. ``` ```hint Test the resolver on its own Write a handful of input and expected-output pairs for path resolution alone, covering `.`, `..`, repeated slashes and attempts to go above the root, before running them through the other methods. ``` #### Clarifying Questions for this Part - What does `..` mean at the root: an error, or stay at the root as a Unix shell does? - If `cd` targets a missing directory or a file, should it fail and leave the current directory unchanged? - Must a path like `missing/../docs` fail because `missing` does not exist, or may `..` be resolved purely by text? #### What This Part Should Cover - One resolution function that turns any absolute or relative input into a canonical path, used by every method - Correct handling of `.`, `..` (including at the root), empty components and trailing slashes - `cd` validates its target before changing any state - Tests that send relative paths through every operation, not only through `cd` ### What a Strong Answer Covers - Working code for both parts, with Part 1 structured so that Part 2 is a small, local change - Path parsing kept separate from tree traversal - Error behavior that is consistent across all methods - A clear explanation of each helper's purpose and design when the interviewer asks mid-implementation - Systematic debugging when a relative-path test fails: isolate the resolver, test it alone, then rerun the operation-level cases - Time complexity in terms of path length and directory size ### Follow-up Questions - Add `rm`. What should happen to a current directory that gets deleted? - Several users share one file system, each with their own current directory. Where does the current directory live now? - Symbolic links are added. Why does resolving `..` purely by text become wrong, and how would you resolve paths instead? - How would you add `~` for a home directory, or a command that returns to the previous directory?

Overview: A multi-part coding exercise that builds an in-memory file system with directories, files and listings over absolute paths, then adds a cd command and relative path support to every operation. It tests tree data structures, path normalization with dot and dot-dot components, consistent error handling and safely refactoring earlier code.

Read the full Perplexity Software Engineer interview experience this question came from

|Home/Software Engineering Fundamentals/Perplexity
Perplexity logo
Perplexity
Oct 2, 2026
mediumSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
3
0

Implement an in-memory file system as a class, in stages. The early stages build a tree of directories and files addressed by absolute paths. The final stage adds a current working directory with a cd command and requires every operation to accept relative paths as well. That final stage is where the difficulty lies: path handling written for absolute paths has to change without breaking what already works, and relative-path bugs are easy to introduce.

The earlier stages are not specified in detail here, so Part 1 states an assumed baseline API. If your interviewer gives a different one, keep its semantics and apply Part 2 to it. Part 2 is the extension the question builds toward.

Clarifying Questions Guidance

  • Are file contents plain strings, and does writing to an existing file overwrite it or append to it?
  • Should ls return names in sorted order, and what should it return when the path is a file?
  • How should errors be reported: exceptions, return values, or silently ignored?
  • Can paths contain repeated slashes or a trailing slash, or are inputs always well formed?

Part 1 — Baseline file system over absolute paths

Implement this API. Every path is absolute: it starts with /, and / alone is the root.

class FileSystem:
    def mkdir(self, path: str) -> None: ...
    def write_file(self, path: str, content: str) -> None: ...
    def read_file(self, path: str) -> str: ...
    def ls(self, path: str) -> list[str]: ...
  • mkdir creates the directory and any missing parent directories. It is an error if some component of the path is an existing file.
  • write_file creates the file or overwrites its content. Its parent directory must already exist, and the path must not name a directory.
  • read_file returns a file's content; the path must name an existing file.
  • ls returns the names of a directory's entries in sorted order, or a one-element list with the file's own name when the path names a file.

What This Part Should Cover Guidance

  • A tree in which directories map names to children and files hold content
  • A single traversal helper shared by all methods
  • Defined behavior for missing paths, a file used as a directory, and the root itself

Part 2 — Add cd and relative paths

Add cd(path), which changes the current working directory, and a pwd() helper that returns the current directory as an absolute path, so the behavior can be tested. The file system starts in /. From now on every method, including cd itself, must accept both absolute paths and relative paths such as docs/a.txt, ./docs or ../shared/b.txt, which are resolved against the current directory.

Clarifying Questions for this Part Guidance

  • What does .. mean at the root: an error, or stay at the root as a Unix shell does?
  • If cd targets a missing directory or a file, should it fail and leave the current directory unchanged?
  • Must a path like missing/../docs fail because missing does not exist, or may .. be resolved purely by text?

What This Part Should Cover Guidance

  • One resolution function that turns any absolute or relative input into a canonical path, used by every method
  • Correct handling of . , .. (including at the root), empty components and trailing slashes
  • cd validates its target before changing any state
  • Tests that send relative paths through every operation, not only through cd

What a Strong Answer Covers Guidance

  • Working code for both parts, with Part 1 structured so that Part 2 is a small, local change
  • Path parsing kept separate from tree traversal
  • Error behavior that is consistent across all methods
  • A clear explanation of each helper's purpose and design when the interviewer asks mid-implementation
  • Systematic debugging when a relative-path test fails: isolate the resolver, test it alone, then rerun the operation-level cases
  • Time complexity in terms of path length and directory size

Follow-up Questions Guidance

  • Add rm . What should happen to a current directory that gets deleted?
  • Several users share one file system, each with their own current directory. Where does the current directory live now?
  • Symbolic links are added. Why does resolving .. purely by text become wrong, and how would you resolve paths instead?
  • How would you add ~ for a home directory, or a command that returns to the previous directory?