cryptomator / cryptofs

Java Filesystem Provider with integrated encryption
GNU Affero General Public License v3.0
93 stars 35 forks source link

Health-API: Implement OrphanDir.fix() #106

Closed infeo closed 3 years ago

infeo commented 3 years ago

This PR implements the OrphanDir::fix method.

The fix is implemented in a way that it restricts itself only to fixing the orphan dir problem. Other problems like a missing or too big dir.c9r are ignored. Hence, the fix must preserve the shortend property of a ciphertext file.

To get an understanding, consider an orphaned ciphertext dir with a shortened file, where content.c9r is missing:

-d/NC/RWII6WWFYQTWWEMBXK4OOLUMUHT6PX
    |- 7HkyoIUdCinG8NxXbwD5hD6nNsE=.c9s
        |- name.c9s
        // missing content.c9s

Since the content.c9s is missing, the file cannot be simply unshortend. By keeping the file shortened, it is ensured that the orphaned directory can be integrated into the vault structure without stopping at these errors.

All files inside the orphaned directory will be moved to a directory with the cleartext path /CRYPTOMATOR_RECOVERY/[DirId-Hash of Orphan]. The name of the "deorphaned" dir is deterministic, such that after an interrupted fix, a new result will continue placing all orphan files into the same deorphaned directory. To prevent FileAlreadyExistsExceptions, each moved resource in the same run is suffixed with a runId.

/CRYPTOMATOR_RECOVERY is a new directory with a unique dir id. All "deorphaned" directories will be located their. It is only created on demand by the fix() method. From the user perspective it will be a normal directory. If a user creates in the vault content root a directory with this name, it won't have the unique id. Every orphanDir fix will fail and the solution is to rename the user generated dir. This can be implemetned as an additonal check or result. If the recovery dir is orphaned itself, just the missing c9r-directory and dirId-file are created and not files moved. An orphaned, user created directory with the same name will stay orphaned and is handled via standard deorphan procedure.

In this context, the Health API is adjusted, that fix(...) throws an IOException-