Back to Harvey questions
CodingSoftware Engineer

Vault File System

Role: Software Engineer


Build an in-memory file directory system that models Harvey's vault — a hierarchical structure of folders and files with capacity limits, deduplication, and file comparison.

Background

At Harvey, users upload files to a vault which is organized like a file directory. Folders can contain files or sub-folders. You'll implement this as an in-memory system across three parts.

Constraints:

  • Each folder is limited to 5 files/sub-folders. Adding beyond this limit returns None (or False)
  • File paths look like path/to/file.txt; folder paths look like path/to/folder
  • All names are alphanumeric — you can assume valid, clean input

Part 1 — Core File System

Implement a Vault class with the following interface:

python
class Vault:
    def add_file(self, path: str) -> bool:
        """Add a file at the given path. Recursively creates folders as needed.
        Returns False if any folder along the path is at capacity (5 items)."""
        ...

    def get_files(self, folder_path: str) -> list[str] | None:
        """Return the names of all direct children of the given folder.
        Not recursive. Returns None if the folder doesn't exist."""
        ...

Example:

python
vault = Vault()
vault.add_file("docs/legal/contract.txt")   # True  — creates docs/, docs/legal/
vault.add_file("docs/legal/nda.txt")        # True
vault.get_files("docs/legal")               # ["contract.txt", "nda.txt"]
vault.get_files("docs")                     # ["legal"]
vault.get_files("nonexistent")              # None

Approach — Trie / nested dict:

Model the file system as a tree. Each node is a folder with a dict of children (sub-folders or files). Files are leaf nodes.

python
from __future__ import annotations
from dataclasses import dataclass, field

MAX_CHILDREN = 5


@dataclass
class Node:
    name: str
    is_file: bool = False
    children: dict[str, Node] = field(default_factory=dict)

    def at_capacity(self) -> bool:
        return len(self.children) >= MAX_CHILDREN


class Vault:
    def __init__(self):
        self._root = Node(name="")

    def _get_node(self, parts: list[str]) -> Node | None:
        current = self._root
        for part in parts:
            if part not in current.children:
                return None
            current = current.children[part]
        return current

    def add_file(self, path: str) -> bool:
        parts = path.split("/")
        current = self._root

        for part in parts[:-1]:  # traverse/create intermediate folders
            if part not in current.children:
                if current.at_capacity():
                    return False
                current.children[part] = Node(name=part)
            current = current.children[part]

        filename = parts[-1]
        if filename in current.children:
            return True  # already exists
        if current.at_capacity():
            return False

        current.children[filename] = Node(name=filename, is_file=True)
        return True

    def get_files(self, folder_path: str) -> list[str] | None:
        parts = folder_path.split("/")
        node = self._get_node(parts)
        if node is None or node.is_file:
            return None
        return list(node.children.keys())

Part 2 — Deduplication (add_files)

Extend the vault with a bulk-add method that skips duplicate files:

python
def add_files(self, paths: list[str]) -> dict[str, bool]:
    """Add multiple files. Skip duplicates (same path already exists).
    Returns a dict mapping each path to True (added) or False (skipped/failed)."""
    ...

What counts as a duplicate? A file at the same path that is already in the vault.

python
vault = Vault()
vault.add_files(["docs/a.txt", "docs/b.txt", "docs/a.txt"])
# → {"docs/a.txt": True, "docs/b.txt": True, "docs/a.txt": False}

Implementation:

python
def add_files(self, paths: list[str]) -> dict[str, bool]:
    results = {}
    seen_in_batch = set()

    for path in paths:
        if path in seen_in_batch:
            results[path] = False
            continue

        added = self.add_file(path)
        results[path] = added
        if added:
            seen_in_batch.add(path)

    return results

Note: The vault already handles the case where add_file is called on an existing path (returns True without re-adding). The seen_in_batch set is only needed to catch duplicates within the same add_files call if you want accurate per-call reporting.


Part 3 — Verifying File Equality

"How do you verify whether two files — their metadata and content — are the same?"

This is a design/discussion question. Two main approaches:

Option A — Iterative File I/O

Read both files chunk by chunk and compare byte-by-byte. Also compare metadata (size, name, last modified).

python
import os

def files_are_equal(path_a: str, path_b: str) -> bool:
    stat_a, stat_b = os.stat(path_a), os.stat(path_b)
    if stat_a.st_size != stat_b.st_size:
        return False  # fast path: sizes differ

    with open(path_a, "rb") as fa, open(path_b, "rb") as fb:
        chunk_size = 8192
        while True:
            chunk_a = fa.read(chunk_size)
            chunk_b = fb.read(chunk_size)
            if chunk_a != chunk_b:
                return False
            if not chunk_a:  # both exhausted simultaneously
                return True

Pros: Exact comparison, no false positives, works on any file size Cons: O(n) reads for every comparison — slow if comparing many files

Option B — Hashing

Compute a cryptographic hash (e.g., SHA-256) of each file's contents. Two files with identical hashes are considered equal.

python
import hashlib

def file_hash(path: str) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()

def files_are_equal(path_a: str, path_b: str) -> bool:
    return file_hash(path_a) == file_hash(path_b)

Pros: Hash can be precomputed and cached — comparing N files is O(N) hashes, then O(1) comparisons Cons: Tiny probability of hash collision (negligible with SHA-256); requires reading the full file once to hash

Option C — Python's filecmp

Python's built-in filecmp.cmp(f1, f2, shallow=False) compares both metadata and content. Simplest for quick use.

python
import filecmp
filecmp.cmp("file_a.txt", "file_b.txt", shallow=False)  # True if identical

Trade-off Summary

ApproachSpeed (one-time)Speed (repeated)False positives
Byte-by-byteO(n)O(n) each timeNone
HashingO(n) to hashO(1) after cachingNegligible
filecmpO(n)O(n)None

In a vault deduplication context: Hashing is ideal — compute and store the hash when a file is uploaded, then compare hashes on subsequent uploads in O(1).


Follow-ups

  • How would you handle the capacity limit at the root level?
  • How would you support move_file(src, dst) — what edge cases arise?
  • If the vault were persisted to disk, how would your deduplication strategy change?
  • How would you make the file system thread-safe for concurrent uploads?
  • What is the time complexity of add_file for a path of depth d?

Variant (independent report)

A second report confirms the same three-part question in a live, screen-shared coding round. The Part 1 prompt below is transcribed verbatim from the on-screen instructions shown to the candidate:

Instructions Part 1

Please share your full screen with your interviewer.

At Harvey, users can upload files to a vault, which is equivalent to a file directory. In the vault, users can setup folders to organize their files. You'll be building an in-memory vault directory system.

Part 1: Setup a file system that can support the following methods:

  • add_file(path): Add a file given a file path. Recursively creates folders.
  • get_files(path) -> str[]: Return the name of the folder's files given a folder path. Not recursive.
  • Constraint: each folder is limited to 5 files/sub-folders. If the limit is reached, return None or False for any subsequent additions.

An example of a file path is path/to/file.txt. An example of a folder path is path/to/folder.

You can also assume you are given valid paths (e.g. no hidden characters), file names are alphanumerics.

Follow-up parts as stated by the interviewer:

Part 2: Deduplicate (add_files) Part 3: explain how you verify whether the two files, meta data/file data is the same

Source: community report, March 2026