2.3 KiB
Resolving paths
Commands that return a path have .realpath variants that resolve it to a
canonical one, with symlinks followed and any . or .. components removed.
The intent is to make paths safer to hand to an external script.
A script called through execute receives whatever path rtorrent gives it, and
many scripts do no sanity checking of their own, so resolving the path before it
leaves rtorrent removes a class of surprises: a download directory that is a
symlink into somewhere unexpected, or a torrent whose name walks upwards out of
the directory it is supposed to live in.
# Instead of this
execute = ~/bin/on-finished, (d.base_path)
# Pass the resolved path
execute = ~/bin/on-finished, (d.base_path.realpath.or_throw)
Available variants
Each command below comes in an .or_empty and an .or_throw form.
| Command | Resolves |
|---|---|
d.base_path.realpath.* |
d.base_path |
d.directory.realpath.* |
d.directory |
d.tied_to_file.realpath.* |
d.tied_to_file |
d.loaded_file.realpath.* |
d.loaded_file |
f.frozen_path.realpath.* |
f.frozen_path |
session.path.realpath.* |
session.path |
directory.default.realpath.* |
directory.default |
A leading ~ is expanded first, exactly as it is for execute, so
~/downloads resolves the same way it would on the command line.
Paths that do not exist
Resolving requires the path to name an existing file or directory, which is often not the case for a download whose data has not been written yet. The two forms differ only in what they do about it.
.or_empty returns an empty string:
print = (d.base_path.realpath.or_empty) # ""
This keeps d.multicall usable over a view that mixes started and unstarted
downloads, since a single unresolvable path does not abort the whole call.
A script receiving one of these paths should still check that it is not empty
before acting on it.
.or_throw raises an error instead:
print = (d.base_path.realpath.or_throw) # Could not resolve path: '...'
Prefer this one wherever an unresolvable path means the command should not run
at all, such as a single execute on event.download.finished.
Note that a download only has a file list once it has been opened, so
d.base_path and f.frozen_path are empty at event.download.inserted time
and their .realpath variants resolve nothing.