summaryrefslogtreecommitdiff
path: root/lib/ffi-xattr
diff options
context:
space:
mode:
authorPatrick J Cherry <patrick@bytemark.co.uk>2015-12-01 22:41:06 +0000
committerPatrick J Cherry <patrick@bytemark.co.uk>2015-12-01 22:41:06 +0000
commit668b9871e64cb82ac30c8defb29d56d774f3c140 (patch)
tree9b4bba7cbcbd2660485cf803402c4d4889e62b10 /lib/ffi-xattr
parent182a03798d49a3c0450b0f137977037cf9376e99 (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.rb47
-rw-r--r--lib/ffi-xattr/error.rb23
-rw-r--r--lib/ffi-xattr/extensions.rb3
-rw-r--r--lib/ffi-xattr/extensions/file.rb9
-rw-r--r--lib/ffi-xattr/extensions/pathname.rb9
-rw-r--r--lib/ffi-xattr/linux_lib.rb52
-rw-r--r--lib/ffi-xattr/version.rb3
-rw-r--r--lib/ffi-xattr/windows_lib.rb45
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