# vim: set noet sw=2 ts=2 sts=2: require 'ffi' require 'pathname' unless Errno.const_defined? :Errnos Errno::Errnos ||= [] Errno.constants. map {|c| Errno.const_get c }. select {|c| c.is_a?( Class) and c.superclass == SystemCallError and c.const_defined?( :Errno) }. each {|c| Errno::Errnos[c::Errno] = c } end module FileDedupeRange extend FFI::Library ffi_lib Pathname.new( __FILE__). dirname.dirname.dirname. join( *%w[ext deduperemoverb deduperemoverb.so]). expand_path. to_s # struct file_dedupe_range_info { # __s64 dest_fd; /* in - destination file */ # __u64 dest_offset; /* in - start of extent in destination */ # __u64 bytes_deduped; /* out - total # of bytes we were able to dedupe from this file. */ # /* status of this dedupe operation: # * < 0 for error # * == FILE_DEDUPE_RANGE_SAME if dedupe succeeds # * == FILE_DEDUPE_RANGE_DIFFERS if data differs # */ # __s32 status; /* out */ # __u32 reserved; /* must be zero */ # }; class Destination < FFI::Struct layout :fd, :int64, :offset, :uint64, :bytes_deduped, :uint64, :status, :int32, :reserved, :uint32 def fd=(i) self[:fd] = i end def fd() self[:fd] end def offset=(i) self[:offset] = i end def offset() self[:offset] end def bytes_deduped() self[:bytes_deduped] end def status() self[:status] end alias initialize_without_defaults initialize def initialize_with_defaults *a initialize_without_defaults *a self[:reserved] = self[:bytes_deduped] = self[:status] = 0 end alias initialize initialize_with_defaults def inspect sprintf "#<%s fd=%d offset=%d bytes_deduped=%d status=%d>", self.class.name, self[:fd], self[:offset], self[:bytes_deduped], self[:status] end end # /* from struct btrfs_ioctl_file_extent_same_args */ # struct file_dedupe_range { # __u64 src_offset; /* in - start of extent in source */ # __u64 src_length; /* in - length of extent */ # __u16 dest_count; /* in - total elements in info array */ # __u16 reserved1; /* must be zero */ # __u32 reserved2; /* must be zero */ # struct file_dedupe_range_info info[0]; # }; class Base < FFI::Struct class <", self.class.superclass.name, self[:dest_count].to_i, self[:offset], self[:length], destinations.map {|d| sprintf "#<%d:%d %d - %d>", d[:fd], d[:offset], d[:bytes_deduped], d[:status] }.join( ',') end end class <