Skip to main content

Linking

With matchMode: "strict", cross-seed will only look for "perfect" matches—candidate file trees that have the exact same file tree, or a strict subset of the file tree, of the data you already have. Then it injects the torrents into your client by mirroring the save path of the torrent you already had.

What is linking?

When a torrent has the same data as another torrent but a different name, you could theoretically seed both torrents by copying the file and renaming it, but this isn't practical—you have to store the data twice even though it's identical. Linking is an alternative to copying that lets two file names point to the same underlying data on disk. There are three types of links: symlinks, hardlinks, and reflinks. cross-seed uses hardlinks by default.

Should I set up linking?

You don't need to set up linking with the matchMode: "strict". However, you will need to set up linking in order to enable the more complete matching strategies such as partial matching or if you want to use data-based matching. When linking is enabled, all injected torrents will be linked, even perfect matches.

info

In order to prevent collisions, cross-seed organizes linked torrents into subfolders of your linkDirs based on the tracker each torrent came from. If you wish to disable this behavior, you can set the flatLinking option to true, but it is not recommended for new users.

Setting up linking

danger

cross-seed AND YOUR TORRENT CLIENT MUST BE ON THE SAME OS TO USE LINKING (DOCKER ALWAYS RUNS ON LINUX, EVEN ON WINDOWS)

If you cannot use linking, you may want to use duplicateCategories: true if you are using sonarr or radarr.

To set up linking, you need to define at least one directory where cross-seed will create links to your existing files and set the linkDirs option to these directories in your config file. These directories should be accessible to your torrent client—cross-seed will use the linkDir on the same device as the save path for the torrents it injects.

If you are utilizing hardlinks or reflinks with Docker, it is necessary that you to use a single mount/volume for each of the linkDirs and the data in your client and/or dataDirs from which you're linking . Using hardlinks across two volumes/mounts in Docker will error and fail.

All paths need to be accessible in the same structure as your torrent client for injection to succeed.

tip

Ideally, you should only have a single linkDir and use drive pooling. Using multiple linkDirs should be reserved for setups with cache/temp drives or where drive pooling is impossible.

In nearly all cases, your linkDir should reside in your torrent client download directory. In the example below, your torrent client download directory would be /mnt/user/data/torrents/.

mnt/
├─ user/
│ ├─ data/
│ | ├─ usenet/
│ | | ├─ movies/
│ | ├─ torrents/
│ | | ├─ tv/
│ | ├─ radarr/
│ | | ├─ Movie/
│ | ├─ sonarr/
│ | | ├─ Show/

Your linkDir would then be:

module.exports = {
// ... other settings ...
linkDirs: ["/mnt/user/data/torrents/SomeLinkDirName"],
};

If you have multiple drives without drive pooling, add more linkDirs as needed for each drive. Once you have restarted cross-seed, new matches will have links created in your linkDirs pointing to the original files.

Docker Users

For Docker Users: there are a few more specific requirements for linking to work properly.

  • Your torrent client will need access to the linkDirs you've set, seeing the same path cross-seed sees.
  • cross-seed's container needs to be able to see the original data files, again at the same path that your torrent client sees.
  • If you are using hardlinks or reflinks, these paths all need to be within the same docker volume.

In practice, this means that you should mount a common ancestor path of the both the original data files and your linkDirs. The example above would require a single mount of /mnt/user/data:/data for BOTH cross-seed and your torrent client. Your linkDir would then be:

module.exports = {
// ... other settings ...
linkDirs: ["/data/torrents/SomeLinkDirName"],
};

By default, cross-seed uses hardlinks to link files because they are resilient to file moves. You can switch the link type by setting the linkType option.

A hardlink is a direct line to the actual data on disk, and as far as the OS is concerned, is indistinguishable from the original file. Because of this, hardlinks are resilient to being moved, and if you delete the original file, any other links to the data will remain intact. The underlying data is deleted once there are zero files left that point to it.

Because hardlinks are implemented at the filesystem layer, they only work within the same mountpoint, so you can't hardlink a file from an internal drive to an external drive. This is especially relevant in Docker setups - Docker volumes are isolated from each other, so hardlink sources and destinations must always be within the same Docker volume, or else linking will fail.

  • Your setup moves files around and you don't want to break links
  • You want to keep cross-seeding torrents even after deleting originals
    • Look into qbit_manage to still be able to delete hardlinked files when originals are deleted

A symlink is a shortcut that stores a path to the original file. OSes have special support for symlinks that allow programs (like torrent clients) to treat them as regular files. Because a symlink itself only contains a file path, if you move or delete the original file, the link will break and trying to open it will throw an ENOENT: no such file or directory error.

  • Your setup doesn't move files around
  • You have separate drives (e.g. for leeching vs seeding) and therefore cannot use hardlinks
  • You want to stop cross-seeding torrents when originals are deleted, but don't use qbit_manage
    • This will present as cross-seeded torrents with missing files errors in your torrent client which you can then bulk delete
  • You prefer errors over accidentally silently copying data

A reflink works similarly to hardlinks until data is written to it. Instead of modifying both files, only the new data is overwritten on the targeted file. This means a reflink with a file starts out identical but can diverge over time if either is modified. This has the same restrictions as hardlink.

  • Your filesystem supports it
  • You want to cross seed the rare files that differ between trackers. Any differences between these two files will not affect the other while still sharing the indentical parts.