From 63af76ae43389057fcec66d6dc799bf38bcec60b Mon Sep 17 00:00:00 2001 From: Jari Bakken Date: Sat, 24 Sep 2011 01:17:48 +0200 Subject: [PATCH] Initial commit --- .gitignore | 4 ++ Gemfile | 4 ++ Rakefile | 8 ++++ ffi-xattr.gemspec | 24 +++++++++++ lib/ffi-xattr.rb | 91 ++++++++++++++++++++++++++++++++++++++++ lib/ffi-xattr/version.rb | 5 +++ 6 files changed, 136 insertions(+) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 Rakefile create mode 100644 ffi-xattr.gemspec create mode 100644 lib/ffi-xattr.rb create mode 100644 lib/ffi-xattr/version.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4040c6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.gem +.bundle +Gemfile.lock +pkg/* diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..38c0679 --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source "http://rubygems.org" + +# Specify your gem's dependencies in ffi-xattr.gemspec +gemspec diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..8224ec1 --- /dev/null +++ b/Rakefile @@ -0,0 +1,8 @@ +require 'bundler' +Bundler::GemHelper.install_tasks + +task :spec do + ruby "lib/ffi-xattr.rb" +end + +task :default => :spec diff --git a/ffi-xattr.gemspec b/ffi-xattr.gemspec new file mode 100644 index 0000000..07b2d54 --- /dev/null +++ b/ffi-xattr.gemspec @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) +require "ffi-xattr/version" + +Gem::Specification.new do |s| + s.name = "ffi-xattr" + s.version = Ffi::Xattr::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Jari Bakken"] + s.email = ["jari.bakken@gmail.com"] + s.homepage = "http://github.com/jarib/ffi-xattr" + s.summary = %q{Manipulate extended file attributes} + s.description = %q{Manipulate extended file attributes} + + s.rubyforge_project = "ffi-xattr" + + s.add_development_dependency "rspec", "~> 2.5" + s.add_dependency "ffi" + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.require_paths = ["lib"] +end diff --git a/lib/ffi-xattr.rb b/lib/ffi-xattr.rb new file mode 100644 index 0000000..c9f304b --- /dev/null +++ b/lib/ffi-xattr.rb @@ -0,0 +1,91 @@ +require 'rubygems' +require 'ffi' + +class Xattr + 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 + end + + def initialize(path) + raise Errno::ENOENT, path unless File.exist?(path) + @path = path + end + + def list + size = Lib.listxattr(@path, nil, 0) + res_ptr = FFI::MemoryPointer.new(:pointer, size) + + Lib.listxattr(@path, res_ptr, size) + res_ptr.read_string.split("\000") + end + + def get(key) + size = Lib.getxattr(@path, key.to_s, nil, 0) + str_ptr = FFI::MemoryPointer.new(:char, size); + Lib.getxattr(@path, key.to_s, str_ptr, size) + + str_ptr.read_string + end + + def set(key, value) + key, value = key.to_s, value.to_s + + check_error Lib.setxattr(@path, key, value, value.bytesize, 0) + end + + def remove(key) + check_error Lib.removexattr(@path, key.to_s) + end + + private + + def check_error(int) + raise "unable to set xattr (#{Lib.strerror FFI.errno})" if int != 0 + end +end + +if __FILE__ == $0 + require 'rspec/autorun' + + describe Xattr do + let(:path) { "test.txt" } + let(:xattr) { Xattr.new(path) } + + before { File.open(path, "w") { |io| io << "some content" } } + after { File.delete(path) } + + it "has an inital empty list of xattrs" do + xattr.list.should be_kind_of(Array) + xattr.list.should be_empty + end + + it "can set and get attributes" do + xattr.set "user.foo", "bar" + xattr.list.should == ["user.foo"] + + xattr.get("user.foo").should == "bar" + end + + it "can remove attributes" do + xattr.set "user.foo", "bar" + xattr.list.should == ["user.foo"] + + xattr.remove "user.foo" + xattr.list.should == [] + end + + it "raises Errno::ENOENT if the file doesn't exist" do + lambda { Xattr.new("no-such-file") }.should raise_error(Errno::ENOENT) + end + + end +end diff --git a/lib/ffi-xattr/version.rb b/lib/ffi-xattr/version.rb new file mode 100644 index 0000000..e78a9f8 --- /dev/null +++ b/lib/ffi-xattr/version.rb @@ -0,0 +1,5 @@ +module Ffi + module Xattr + VERSION = "0.0.1" + end +end