Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions documentation/docs/features/cross-seed/hardlink-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Reflink mode creates copy-on-write clones of the matched files. Unlike hardlinks
### When to Use Reflink Mode

- You want to cross-seed torrents that hardlink mode would skip due to "extra files share pieces with content"
- Your filesystem supports copy-on-write clones (BTRFS, XFS on Linux; APFS on macOS)
- Your filesystem supports copy-on-write clones (BTRFS, XFS on Linux; APFS on macOS; ReFS on Windows)
- You prefer the safety of copy-on-write over hardlinks

### Reflink Requirements
Expand All @@ -99,7 +99,12 @@ Reflink mode creates copy-on-write clones of the matched files. Unlike hardlinks
- The filesystem must support reflinks:
- **Linux**: BTRFS, XFS (with reflink=1), and similar CoW filesystems
- **macOS**: APFS
- **Windows/FreeBSD**: Not currently supported
- **Windows**: ReFS on the same volume as the source files and reflink base directory
- **FreeBSD**: Not currently supported

:::note
Windows reflink mode uses ReFS block cloning (requiring an ReFS filesystem). NTFS is not supported. If reflink creation fails, fallback still depends on the existing "Fallback to regular mode" setting.
:::

:::tip
On Linux, check the filesystem type with `df -T /path` (you want `xfs`/`btrfs`, not `fuseblk`/`fuse.mergerfs`/`overlayfs`).
Expand Down
6 changes: 5 additions & 1 deletion internal/services/crossseed/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11081,7 +11081,11 @@ func (s *Service) processReflinkMode(

// Create reflink tree on disk
if err := reflinktree.Create(plan); err != nil {
log.Error().
logEvent := log.Error()
if errors.Is(err, reflinktree.ErrReflinkUnsupported) {
logEvent = log.Warn()
}
logEvent.
Err(err).
Int("instanceID", candidate.InstanceID).
Str("torrentName", torrentName).
Expand Down
8 changes: 4 additions & 4 deletions pkg/reflinktree/reflink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ func TestSupportsReflink(t *testing.T) {

supported, reason := SupportsReflink(tmpDir)

// On unsupported platforms, should return false
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
// On unsupported platforms, should return false.
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
if supported {
t.Errorf("SupportsReflink should return false on %s", runtime.GOOS)
}
Expand All @@ -28,8 +28,8 @@ func TestSupportsReflink(t *testing.T) {
return
}

// On supported platforms, the result depends on filesystem
// We just verify the function doesn't panic and returns sensible values
// On supported platforms, the result depends on filesystem.
// We just verify the function doesn't panic and returns sensible values.
t.Logf("SupportsReflink(%s): supported=%v, reason=%s", tmpDir, supported, reason)

if !supported {
Expand Down
4 changes: 2 additions & 2 deletions pkg/reflinktree/reflink_unsupported.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright (c) 2025-2026, s0up and the autobrr contributors.
// SPDX-License-Identifier: GPL-2.0-or-later

//go:build !linux && !darwin
//go:build !linux && !darwin && !windows

package reflinktree

// SupportsReflink returns false on unsupported platforms.
// Windows and FreeBSD do not have a standard reflink mechanism that we support.
// FreeBSD do not have a standard reflink mechanism that we support.
func SupportsReflink(_ string) (supported bool, reason string) {
return false, "reflink is not supported on this operating system"
}
Expand Down
Loading
Loading