diff options
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 |