Katkat

Implement an In-Memory File System

ShopifySoftware Engineer · Onsite

Last updated

Implement an in-memory file system with absolute and relative path resolution, sorted listing, directory changes, creation, and removal. Enforce deterministic error codes, atomic validation, recursive deletion rules, and protection for the current directory and its ancestors.

Implement an In-Memory File System

The source reports an in-memory file-system exercise but not its exact error serialization or current-directory removal policy. The error codes, driver, and busy-directory rule below are deterministic practice assumptions.

Implement:

class FileSystemError(Exception):
 code: str

class FileSystem:
 def ls(self, path: str = ".") -> list[str]: ...
 def cd(self, path: str) -> None: ...
 def add(self, path: str, is_directory: bool) -> None: ...
 def remove(self, path: str, recursive: bool = False) -> None: ...

def run_file_system(operations: list[list[object]]) -> list[object]:
 ...

The file system starts with an empty root / and current working directory /. Directories contain named children; files contain no data.

Paths and Successful Results

  • Support absolute and relative paths, repeated /, ., .., and trailing separators. Traversal above root stays at root. An empty path string is invalid.
  • ls(path) returns sorted child names for a directory and [basename] for a file.
  • cd(path) changes the working directory only when the resolved target is a directory and returns None.
  • add(path, is_directory) creates exactly one file or directory. The resolved parent must already be a directory, and the target must not exist. Success returns None.
  • remove(path, recursive=False) removes a file or empty directory. A nonempty directory requires recursive=True. Success returns None.

Resolve the complete path before mutating anything. A file may be the final target of ls or remove, but no operation may traverse through a file.

Deterministic Errors

Class methods raise FileSystemError with exactly one of these codes:

  • "invalid_path": the path is not a nonempty string.
  • "not_found": a required component or target is absent.
  • "not_directory": traversal would continue through a file, or cd targets a file.
  • "already_exists": add resolves to an existing node.
  • "root": remove targets /.
  • "busy": remove targets the current working directory or any of its ancestors, even with recursive=True.
  • "directory_not_empty": a non-busy, non-root directory has children and recursive=False.

For remove, resolve first, then apply error precedence root, busy, and directory_not_empty. Resolution errors occur before those checks. Every failed class operation is atomic: the tree and current working directory remain unchanged.

The driver uses these commands:

  • ["LS"] or ["LS", path]
  • ["CD", path]
  • ["ADD", path, is_directory]
  • ["REMOVE", path] or ["REMOVE", path, recursive]

It returns one result per operation. On a successful command, append the method's result. On FileSystemError, append ["ERROR", code] and continue. A malformed command, unknown command, or non-Boolean flag appends ["ERROR", "invalid_operation"] without calling a class method.

Performance and Tests

Aim for time proportional to normalized path components plus returned output, except that recursive deletion is proportional to the removed subtree. Test above-root traversal, repeated separators, traversal through files, duplicate adds, failed cd, removing root, removing the current directory and each ancestor, recursive removal of an unrelated subtree, failure atomicity, and error precedence.