Original Problem

We have two directories plaintext and secret, which hold the unencrypted files and their encrypted counter parts respectively. We need to detect changes to plaintext and sync them to secret.

Common Methods

Polling Based

The simplest method is to check the directory on a regular interval (polling) for changes by walking the directory and its files and comparing it against the cached last known state. This method can be less efficient and timely than the other two methods below but it’s biggest advantage is it is the least OS dependent.

Event Based

Event based watchers rely on the kernel to notify them of events related to the file’s or directories they’re watching.

inotify is a linux subsystem that allows you to setup a watch on a file or a directory and receive notifications on relevant changes. kqueue is another alternative that can monitor events for more than just files however has the drawback of opening a file descriptor for every file and directory it’s monitoring which increases the likelihood of hitting the OS file descriptor limit.

FUSE

FUSE allows you to treat a directory as a filesystem and your program intercepts all I/O on that file system. This allows you to have the secret directory as normal, but plaintext is optionally only available while the program is running. This is is what cryptomator, gocryptFS, and other file system encryption approaches do. There’s no direct equivalent in windows I could find except for winfsp which is not by Microsoft.

What solution is best for me?

The command line watcher utility watchexec I used in the POC uses the rust notify library which uses the best available notification system on the platform it’s running (inotify, kqueue, ReadDirectoryChangesW)

In my current situation, I don’t need the plaintext directory to be unavailable since I’m using it on my personal laptop that no one has access to. However, I do envision a scenario where I’ll want to decrypt or explore the files on a different computer that I don’t completely trust. I think polishing my original approach the watches the directory should be my first priority followed by adding support that uses FUSE.