Module: FileUtils

Defined in:
lib/pocolog/cp_cow.rb

Defined Under Namespace

Modules: IOCTL Classes: ReflinkUnsupported

Constant Summary

BTRFS_IOC_CLONE =
IOCTL.IOW(0x94, 9, 4)

Class Method Summary collapse

Class Method Details

.cp_cow(from_path, to_path, strategies: [:reflink, :cp]) ⇒ Object

Attempts to copy using CoW if possible

Parameters:

  • strategies (Array<Symbol>)

    to try. It is a list of :reflink, :hardlink, :cp. The default is :reflink and :cp, :hardlink being usable only if the source and target files are meant to be read-only



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pocolog/cp_cow.rb', line 80

def self.cp_cow(from_path, to_path, strategies: [:reflink, :cp])
    strategies.each do |s|
        case s
        when :reflink
            begin
                cp_reflink(from_path, to_path)
                return :reflink
            rescue ReflinkUnsupported
            end
        when :hardlink
            begin
                FileUtils.ln from_path, to_path
                return :hardlink
            rescue Errno::EPERM
                # This is what we get on filesystems that do not support
                # hardlinks
            end
        when :cp
            # We assume that 'cp' should always work
            FileUtils.cp from_path, to_path
            return :cp
        else
            raise ArgumentError, "unknown strategy for cp_cow #{s}, expected one of :reflink, :hardlink or :cp"
        end
    end
end

Copies a file, using reflink the way cp –reflink would if possible

Parameters:

  • from_path (String)

    the path to the file that will be copied

  • to_path (String)

    the path to the destination file

Returns:

  • (Boolean)

    true if the copy has used reflink, false if it was a plain copy

Raises:

  • (ReflinkUnsupported)

    if the underlying platform does not have reflink (which you can also test with may_have_reflink?)



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/pocolog/cp_cow.rb', line 57

def self.cp_reflink(from_path, to_path)
    if may_have_reflink?
        from_io = File.open(from_path, 'r')
        to_io   = File.open(to_path, 'w')
        begin
            to_io.ioctl(BTRFS_IOC_CLONE, from_io.fileno)
        rescue Errno::EXDEV
            raise ReflinkUnsupported, "cannot reflink while crossing filesystem boundaries (from #{from_path} to #{to_path})"
        rescue Errno::ENOTTY
            raise ReflinkUnsupported, "the backing filesystem of #{from_path} does not support reflinks"
        rescue Errno::EOPNOTSUPP
            raise ReflinkUnsupported, "reflinks are not supported on this platform"
        end
    else
        raise ReflinkUnsupported, "reflinks are not supported on this platform"
    end
end

.may_have_reflink?Boolean

Check if the host platform may have reflink support

Returns:

  • (Boolean)


45
46
47
# File 'lib/pocolog/cp_cow.rb', line 45

def self.may_have_reflink?
    @may_have_reflink
end