Skip to main content

Overview

This page documents the exact structure of each object type in the Cloudstic storage model. All objects are stored as JSON (except chunks, which are raw binary) and keyed by their hash.

Chunk

Object key: chunk/<hmac_sha256> or chunk/<sha256> Format: Raw binary (zstd-compressed bytes) Chunks are the only non-JSON objects in the system. They contain raw file data compressed with zstd.

Content-Defined Chunking

Chunks are produced by FastCDC (Fast Content-Defined Chunking): The final chunk of a file may be smaller than the minimum.

Hash Function

  • When encrypted: HMAC-SHA256(dedup_key, uncompressed_data)
    • The dedup key is derived from the encryption key via HKDF
    • Prevents the storage provider from confirming file contents by hashing known plaintext
  • When unencrypted: SHA-256(uncompressed_data)
The hash is computed on the uncompressed data, not the stored zstd-compressed bytes. This ensures consistent deduplication regardless of compression settings.

Storage Format

Reading a chunk:
  1. Fetch the object bytes
  2. Decompress with zstd
  3. Return the raw file data

Content

Object key: content/<sha256-of-raw-file-content> Format: JSON object Content objects list the ordered chunks that make up a file’s content.

Go Struct Definition

From internal/core/models.go:

Inline Data Optimization

Very small files (< 512 KiB) may use data_inline_b64 instead of chunks to avoid creating a separate chunk object:
This reduces object count and API calls for small files.

FileMeta

Object key: filemeta/<sha256-of-serialized-json> Format: JSON object FileMeta objects contain immutable metadata about a file or folder.

Go Struct Definition

From internal/core/models.go:

Field Descriptions

Important: fileId is the HAMT key used to look up this file’s metadata. It must be unique within a snapshot.

Folder Representation

Folders are represented with:
  • type: "folder"
  • content_hash: "" (empty string)
  • content_ref: "" (empty string)
  • size: 0
  • chunks: [] in the content object (if created)

Parent References

The parents field contains refs to parent FileMeta objects, not raw file IDs. This allows reconstructing the full directory path by walking the parent chain, which is now the primary restore/listing model for new snapshots.

HAMT Node

Object key: node/<sha256-of-serialized-json> Format: JSON object See HAMT Structure for detailed documentation.

Internal Node

Leaf Node

Go Struct Definition

From internal/core/models.go:

Snapshot

Object key: snapshot/<sha256-of-serialized-json> Format: JSON object Snapshots are point-in-time backup checkpoints referencing a HAMT root.

Go Struct Definition

From internal/core/models.go:

Field Descriptions

Every snapshot is a complete checkpoint, with no delta replay needed. Structural sharing via the HAMT minimizes the number of new nodes.

Change Tokens

Incremental sources (gdrive-changes, onedrive-changes) record an opaque change_token in each snapshot. On the next backup:
  1. Read the token from the previous snapshot
  2. Pass it to the source to get only changed files since that token
  3. Save the new token in the new snapshot
If no previous token exists (first backup or after switching from a full-scan source), the source performs a full scan and saves the initial token.

Index Objects

index/latest

Object key: index/latest Format: JSON object A mutable pointer to the most recent snapshot.

index/snapshots

Object key: index/snapshots Format: JSON array A catalog of lightweight snapshot summaries, used to avoid fetching each full snapshot object:
The catalog self-heals via reconciliation with LIST snapshot/ on load. If the catalog is missing or stale, it’s rebuilt automatically.

index/packs

Object key: index/packs Format: bbolt database When packfiles are enabled, the pack catalog is a bbolt key-value database mapping logical object keys to their location within packfiles:
The catalog is stored as a single object in the store and loaded into memory on startup.

Encryption Key Slots

Object key: keys/<slot_type>-<label> (e.g. keys/password-default) Format: JSON object (stored unencrypted) Key slots wrap the repository’s master encryption key using various methods.

Go Struct Definition

Password Slot

The master key is wrapped with a key derived from the password via Argon2id:

Platform Slot

The master key is wrapped directly with a raw 32-byte platform key (no KDF):

Recovery Slot

The master key is wrapped with a key derived from a BIP39 24-word mnemonic:

KMS-Platform Slot

A platform key is wrapped by AWS KMS; the KMS-wrapped platform key is then used to unwrap the master key:
Key slots are stored unencrypted under the keys/ prefix, which the EncryptedStore passes through. Only the wrapped master key is encrypted (AES-256-GCM).

Repository Config

Object key: config Format: JSON object (stored unencrypted) The repository marker written by init:
This object is stored unencrypted so that clients can determine whether the repository requires decryption before attempting to read key slots.