SealSkin

filesync

Keeping every user's shared files in the object store.

A session mounts its user's shared files at Desktop/files. With more than one node, the store holds the copy every node works from. A session starts without waiting for the files: the node's copy catches up in the background as the session comes up (pull_later), and a launch that opens one file of the directory fetches that file alone first (pull_file). What a session changed is sent when it stops and every few minutes while it runs (sync). Files are written whole and moved into place, so a running session never sees a half-written one, and never through a symbolic link: a user's link in the directory, which a session can make, is not followed (_place).

Each file is the object files/<user>/<path>, encrypted under the user's key when the cluster has one (filecrypt). A node remembers the entity tag, size, and time of every file as of its last sync, which tells a file changed here from one changed elsewhere. The last writer wins; when both sides changed a file, this node's version is kept beside the store's under a .conflict-<node> name. Files larger than MAX_BYTES stay on their node, and a file this node cannot decrypt is left as it is on both sides.

attributelogger
= logging.getLogger(__name__)
attributeMAX_BYTES
= 512 * 1024 * 1024
funcenabled() -> bool

Whether shared files are synced: files_sync on, or auto with a second node in the cluster.

Returns

bool
func_manifest_path(username) -> str

Return where this node remembers a user's last sync.

paramusernamestr

Returns

str
func_local_files(root) -> dict[str, tuple[int, int]]

Return the size and modification time of every regular file under root by relative path.

paramrootstr

Returns

dict[str, tuple[int, int]]
func_place(root, name) -> str | None

Return where the shared file name goes under root, or None when the path leaves the directory or crosses a link.

The directory is a session's to write, so a link in it may point anywhere; a file is placed only where every directory on its way is a real one under the root, and never over a link.

paramrootstr
paramnamestr

Returns

str | None
func_write(target, data, tag) -> dict[str, Any]

Write a file whole beside its place and move it there, and return its manifest entry.

paramtargetstr
paramdatabytes
paramtagstr

Returns

dict[str, typing.Any]
func_pull_file(username, root, name) -> bool

Fetch one of a user's shared files from the store unless this node's copy is current; return whether it is here.

paramusernamestr
paramrootstr
paramnamestr

Returns

bool
func_sync(username, root, send) -> None

Bring root and the store's copy of a user's shared files together.

paramusernamestr

Owner of the files.

paramrootstr

The user's shared files directory on this node.

paramsendbool

Also send what changed here; a pull before a launch sends nothing.

Returns

None
func_run(username, root, send) -> None

Sync in a thread and log, rather than raise, what goes wrong.

paramusernamestr
paramrootstr
paramsendbool

Returns

None
funcpull(username, root) -> None

Bring a user's shared files on this node up to date, taking what the store has and sending nothing.

paramusernamestr
paramrootstr

Returns

None
funcpull_later(username, root) -> None

Bring a user's shared files up to date in the background, as a session starts over them.

paramusernamestr
paramrootstr

Returns

None
funcpull_file(username, root, name) -> bool

Fetch the one shared file a launch opens, and say whether it is on this node.

paramusernamestr

Owner of the files.

paramrootstr

The user's shared files directory on this node.

paramnamestr

The file's path under the directory.

Returns

bool
funcforget(username) -> None

Remove a deleted user's shared files from the store, and the key they were encrypted under.

paramusernamestr

Returns

None
funcsync(username, root) -> None

Send what changed in a user's shared files here and take what changed elsewhere.

paramusernamestr
paramrootstr

Returns

None
funcpush_later(username, root) -> None

Sync a user's shared files in the background, as when a session stops.

paramusernamestr
paramrootstr

Returns

None