Skip to content
Work in progress — do not trust Drivel with your only copy. It is unfinished, under-tested, and may lose data. Keep backups you have checked. What this means →
Data safety

Data safety

What Drivel does when things disagree, and the rules it will not break. Worth reading once before pointing it at data you care about.

The backing directory is the source of truth

Everything you do on the mount lands in the backing directory first, as an ordinary file, and syncs afterwards. Filesystem operations never wait on the network, and they never fail because Google is slow or unreachable — they succeed locally, and the upload retries in the background.

The practical consequence: your files survive Drivel. Unmount it, delete it, lose your credentials — the backing directory is still a directory of files.

Conflicts

Drivel syncs both ways, so the same file can change on two machines between polls. When a remote change arrives for a file that also changed locally since the last successful sync, Drivel resolves it last-writer-wins by modification time and keeps the loser as a conflict copy beside it:

report.txt
report (conflict 2026-09-07 14-22-08).txt

Nothing is discarded. The copy is yours to inspect, merge, or delete.

Conflict copies are local-only by policy and are never uploaded — uploading them would publish the losing side of every conflict you have ever had, to every device you sync. The enumeration sweep skips them for the same reason.

A conflict copy is only created when both sides genuinely diverged from the last synced state. A remote change to a file you have not touched is simply applied, and a local change that has not yet uploaded is simply uploaded.

Deletion

This is the half of syncing that can lose data, so it is guarded hard.

A deletion made while Drivel is running is unambiguous — it saw the operation — and propagates like any other change.

A deletion inferred while Drivel was not running is the dangerous case, and Drivel infers one only from a baseline: a record that it previously synced that exact path. A file being absent on one side is not evidence. Without a baseline, “created on the other side” and “deleted on this side” are the same observation, so a path Drivel has never synced is treated as new, whichever side it is on.

That single rule has a consequence worth stating plainly: the first run never deletes anything.

Four further guards:

  1. Deletions run only after a complete enumeration. An interrupted sweep deletes nothing.
  2. The baseline must predate the sweep — otherwise a file you created locally during the sweep would look remotely deleted.
  3. A local file that changed since its baseline is kept and pushed back, never deleted. Divergence beats absence.
  4. -max-deletes (default 100) abandons the whole delete pass if the count looks wrong, rather than trimming it. A very large count means the premise is broken — a state database reused against a different Drive folder, an empty backing directory, a mount pointing somewhere unexpected — not that there are 4000 real deletions.

If the deletions really were genuine, re-run with -resync and a higher cap together. Raising the cap alone does nothing until the next scheduled sweep, because a refused pass still counts as a completed one. Drivel’s refusal message says so.

Where a deleted file goes

A remote deletion is a move to the Drive trash, so it is recoverable from drive.google.com for 30 days. That is the default because of everything above: a deletion Drivel inferred rests on a premise, and a premise can be wrong. The trash is the last guard, the one that works after all the others have been satisfied by a mistake.

It is a real removal all the same. The path is gone, your other machines delete their copies, and a folder takes its contents with it — Drive’s trash hides the whole subtree, not just the folder. What survives is the ability to put it back.

Two consequences: a trashed file still counts against your Drive quota until you empty the trash, and deleting a file and recreating it under the same name leaves the old copy in the trash beside the new one.

-drive-delete permanent restores the old behaviour — the API’s outright delete, no undo anywhere — which is what you want if the mount is how you reclaim space. The cap in guard 4 applies either way: a thousand files in your trash is better than a thousand files gone, and still not what you asked for.

Files Drivel does not sync

  • Google-native documents (Docs, Sheets, Slides) have no byte stream, so there is no honest size for a placeholder and no content to compare. They are listed and counted — so their absence is never mistaken for a deletion — but never materialised locally.
  • Symlinks, sockets, FIFOs and device nodes are created normally in the backing directory and stay there. They have no byte stream, and Drive has no representation for them. Drivel now logs one line naming each one it steps over, from the mount when you create it and from the enumeration sweep when it walks past it, so a file that is not syncing says so instead of just being absent on your other machines.
  • Hard links are refused with Operation not permitted — see below.
  • Extended attributes are never synced, in either direction, whatever -xattr is set to.
  • Conflict copies and Drivel’s own temporary files (.drivel-*).

Hard links

ln, cp -l and anything else asking for a hard link on the mount fails with EPERM (Operation not permitted), which is the error link(2) defines for a filesystem that cannot make them.

This is a refusal, not a bug. What a hard link buys — two names, one inode, one copy of the bytes — is exactly what a cloud store addressed by path cannot express. Earlier versions let the link succeed, and it was worse than it looked: the two names were then ordinary regular files, so both were uploaded, as two independent objects that diverged from each other on the first write. You were told the link worked and got two files that quietly stopped agreeing.

Symlinks still work; only hard links are refused.

Mount safety options

Drivel always mounts nodev and nosuid, and there is no flag to turn them off. A device node or a setuid binary arriving from a remote is never something you asked for, so nothing at the mountpoint can gain privilege or reach a device.

This covers the mountpoint, not the backing directory. With -data the backing directory is an ordinary directory on an ordinary filesystem, reachable without going through Drivel at all — so if you put a setuid binary there yourself, it is live there. Drivel never sets those bits on your behalf.

Same-name siblings

Google Drive permits two files with the same name in the same folder; POSIX does not. Two clients creating the same path at the same time can produce exactly that.

When it happens, Drivel picks the most recently modified and logs that the others are now invisible. Be aware of what a fleet then sees: deleting the file removes only the visible one, so the path can reappear with an older sibling’s content, everywhere. Every available mitigation loses something someone wrote or makes path resolution non-deterministic, so Drivel tells you rather than choosing for you. Resolve it in the Drive web UI by renaming or deleting the duplicates.

The databases are caches

Drivel keeps two small bbolt databases: sync state (the change cursor and the sync baselines) and, for Drive, a path↔file-ID index. Neither is authoritative for anything.

Deleting the index costs API round trips and nothing else — every stored mapping is re-verified against Drive before it is used anyway, because the object may have been moved or replaced while Drivel was down.

Deleting the sync-state database costs you the baselines, which means the next run behaves like a first run: it deletes nothing, re-pushes what it cannot account for, and re-enumerates. Inconvenient, never destructive.

What is not recoverable is the lazy-mode placeholder marker , which lives on the file itself and has no database fallback by design.

What Drivel never does

  • Upload a placeholder over your remote file.
  • Splice partial changes into a remote file that has diverged from what it last synced — it falls back to a whole-file upload, or a conflict copy.
  • Delete anything on the first run.
  • Publish a conflict copy.
  • Create a hard link, or let one become two diverging remote files.
  • Re-serialize your config file, discarding comments.