summaryrefslogtreecommitdiff
path: root/lib/ffi-xattr
diff options
context:
space:
mode:
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