diff options
author | Patrick J Cherry <patrick@bytemark.co.uk> | 2015-12-01 22:41:06 +0000 |
---|---|---|
committer | Patrick J Cherry <patrick@bytemark.co.uk> | 2015-12-01 22:41:06 +0000 |
commit | 668b9871e64cb82ac30c8defb29d56d774f3c140 (patch) | |
tree | 9b4bba7cbcbd2660485cf803402c4d4889e62b10 /lib/ffi-xattr | |
parent | 182a03798d49a3c0450b0f137977037cf9376e99 (diff) |
Completely re-vamped restore command. Fixes #12403
The byteback-restore command now uses the rsync xattrs to display
information about the files due to be restored. It can handle filenames
with spaces (!) and other characters.
Diffstat (limited to 'lib/ffi-xattr')
-rw-r--r-- | lib/ffi-xattr/darwin_lib.rb | 47 | ||||
-rw-r--r-- | lib/ffi-xattr/error.rb | 23 | ||||
-rw-r--r-- | lib/ffi-xattr/extensions.rb | 3 | ||||
-rw-r--r-- | lib/ffi-xattr/extensions/file.rb | 9 | ||||
-rw-r--r-- | lib/ffi-xattr/extensions/pathname.rb | 9 | ||||
-rw-r--r-- | lib/ffi-xattr/linux_lib.rb | 52 | ||||
-rw-r--r-- | lib/ffi-xattr/version.rb | 3 | ||||
-rw-r--r-- | lib/ffi-xattr/windows_lib.rb | 45 |
8 files changed, 191 insertions, 0 deletions
diff --git a/lib/ffi-xattr/darwin_lib.rb b/lib/ffi-xattr/darwin_lib.rb new file mode 100644 index 0000000..59f0810 --- /dev/null +++ b/lib/ffi-xattr/darwin_lib.rb @@ -0,0 +1,47 @@ +class Xattr # :nodoc: all + module Lib + extend FFI::Library + + ffi_lib "System" + + attach_function :listxattr, [:string, :pointer, :size_t, :int], :ssize_t + attach_function :getxattr, [:string, :string, :pointer, :size_t, :uint, :int], :ssize_t + attach_function :setxattr, [:string, :string, :pointer, :size_t, :uint, :int], :int + attach_function :removexattr, [:string, :string, :int], :int + + XATTR_NOFOLLOW = 0x0001 + + class << self + def list(path, no_follow) + options = no_follow ? XATTR_NOFOLLOW : 0 + size = listxattr(path, nil, 0, options) + res_ptr = FFI::MemoryPointer.new(:pointer, size) + listxattr(path, res_ptr, size, options) + + res_ptr.read_string(size).split("\000") + end + + def get(path, no_follow, key) + options = no_follow ? XATTR_NOFOLLOW : 0 + size = getxattr(path, key, nil, 0, 0, options) + return unless size > 0 + + str_ptr = FFI::MemoryPointer.new(:char, size) + getxattr(path, key, str_ptr, size, 0, options) + + str_ptr.read_string(size) + end + + def set(path, no_follow, key, value) + options = no_follow ? XATTR_NOFOLLOW : 0 + Error.check setxattr(path, key, value, value.bytesize, 0, options) + end + + def remove(path, no_follow, key) + options = no_follow ? XATTR_NOFOLLOW : 0 + Error.check removexattr(path, key, options) + end + end + + end +end diff --git a/lib/ffi-xattr/error.rb b/lib/ffi-xattr/error.rb new file mode 100644 index 0000000..602053d --- /dev/null +++ b/lib/ffi-xattr/error.rb @@ -0,0 +1,23 @@ +class Xattr # :nodoc: all + module Error + extend FFI::Library + + ffi_lib "c" + + attach_function :strerror_r, [:int, :pointer, :size_t], :int unless RUBY_PLATFORM =~ /mingw/ + + class << self + def last + errno = FFI.errno + ptr = FFI::MemoryPointer.new(:char, 256) + strerror_r(errno, ptr, 256) + + [ ptr.read_string, errno ] + end + + def check(int) + raise SystemCallError.new(*last) if int != 0 + end + end + end +end diff --git a/lib/ffi-xattr/extensions.rb b/lib/ffi-xattr/extensions.rb new file mode 100644 index 0000000..4ecad8a --- /dev/null +++ b/lib/ffi-xattr/extensions.rb @@ -0,0 +1,3 @@ +require 'ffi-xattr/extensions/file' +require 'ffi-xattr/extensions/pathname' + diff --git a/lib/ffi-xattr/extensions/file.rb b/lib/ffi-xattr/extensions/file.rb new file mode 100644 index 0000000..200f024 --- /dev/null +++ b/lib/ffi-xattr/extensions/file.rb @@ -0,0 +1,9 @@ +require 'ffi-xattr' + +class File + + # Returns an Xattr object for the named file (see Xattr). + def self.xattr(file_name) + Xattr.new(file_name) + end +end diff --git a/lib/ffi-xattr/extensions/pathname.rb b/lib/ffi-xattr/extensions/pathname.rb new file mode 100644 index 0000000..c2ed11e --- /dev/null +++ b/lib/ffi-xattr/extensions/pathname.rb @@ -0,0 +1,9 @@ +require 'ffi-xattr/extensions/file' + +class Pathname + # Returns an Xattr object. + # See File.xattr. + def xattr + File.xattr(self) + end +end diff --git a/lib/ffi-xattr/linux_lib.rb b/lib/ffi-xattr/linux_lib.rb new file mode 100644 index 0000000..e90a8ad --- /dev/null +++ b/lib/ffi-xattr/linux_lib.rb @@ -0,0 +1,52 @@ +class Xattr # :nodoc: all + module Lib + extend FFI::Library + + ffi_lib "c" + + attach_function :strerror, [:int], :string + + attach_function :listxattr, [:string, :pointer, :size_t], :size_t + attach_function :setxattr, [:string, :string, :pointer, :size_t, :int], :int + attach_function :getxattr, [:string, :string, :pointer, :size_t], :int + attach_function :removexattr, [:string, :string], :int + + attach_function :llistxattr, [:string, :pointer, :size_t], :size_t + attach_function :lsetxattr, [:string, :string, :pointer, :size_t, :int], :int + attach_function :lgetxattr, [:string, :string, :pointer, :size_t], :int + attach_function :lremovexattr, [:string, :string], :int + + class << self + def list(path, no_follow) + method = no_follow ? :llistxattr : :listxattr + size = send(method, path, nil, 0) + res_ptr = FFI::MemoryPointer.new(:pointer, size) + send(method, path, res_ptr, size) + + res_ptr.read_string(size).split("\000") + end + + def get(path, no_follow, key) + method = no_follow ? :lgetxattr : :getxattr + size = send(method, path, key, nil, 0) + return unless size > 0 + + str_ptr = FFI::MemoryPointer.new(:char, size) + send(method, path, key, str_ptr, size) + + str_ptr.read_string(size) + end + + def set(path, no_follow, key, value) + method = no_follow ? :lsetxattr : :setxattr + Error.check send(method, path, key, value, value.bytesize, 0) + end + + def remove(path, no_follow, key) + method = no_follow ? :lremovexattr : :removexattr + Error.check send(method, path, key) + end + end + + end +end diff --git a/lib/ffi-xattr/version.rb b/lib/ffi-xattr/version.rb new file mode 100644 index 0000000..eaafe38 --- /dev/null +++ b/lib/ffi-xattr/version.rb @@ -0,0 +1,3 @@ +class Xattr + VERSION = "0.1.2" +end diff --git a/lib/ffi-xattr/windows_lib.rb b/lib/ffi-xattr/windows_lib.rb new file mode 100644 index 0000000..d4199cc --- /dev/null +++ b/lib/ffi-xattr/windows_lib.rb @@ -0,0 +1,45 @@ +# encoding: utf-8 +require 'ffi-xattr' + +class Xattr # :nodoc: all + module Lib + class << self + + def list(path, no_follow) + lines = `dir /r "#{path}"`.split("\n") + + xattrs = [] + lines.each { |line| + if line =~ /\:\$DATA$/ + size = line.split(' ')[0].gsub(/[^0-9]/,'').to_i + + if size > 0 + xattrs << line.split(':')[1] + end + end + } + xattrs + end + + def get(path, no_follow, key) + fp = "#{path}:#{key}" + if File.exists?(fp) + File.binread(fp) + else + raise "No such key. #{key.inspect} #{path.inspect}" + end + end + + def set(path, no_follow, key, value) + File.open("#{path}:#{key}",'wb') { |io| io << value } + end + + def remove(path, no_follow, key) + # done this way because Windows have no function to remove Alternate Data Stream + # quickest way is to set the value to 0 byte length instead of trying to create another file then apply the attributes, especially when dealing with a big file + self.set(path, false, key, '') + end + end + + end +end |