ffi-xattr 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.travis.yml +6 -0
- data/README.md +5 -7
- data/Rakefile +2 -0
- data/ffi-xattr.gemspec +3 -1
- data/lib/ffi-xattr/darwin_lib.rb +27 -20
- data/lib/ffi-xattr/error.rb +11 -9
- data/lib/ffi-xattr/linux_lib.rb +37 -26
- data/lib/ffi-xattr/version.rb +1 -3
- data/lib/ffi-xattr.rb +14 -7
- data/spec/xattr_spec.rb +66 -0
- metadata +79 -37
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -3,23 +3,21 @@ ffi-xattr
|
|
3
3
|
|
4
4
|
Ruby library to manage extended file attributes.
|
5
5
|
|
6
|
+
[](http://travis-ci.org/jarib/ffi-xattr)
|
7
|
+
|
8
|
+
|
6
9
|
Example
|
7
10
|
-------
|
8
11
|
|
9
12
|
xattr = Xattr.new("/path/to/file")
|
10
13
|
xattr['user.foo'] = 'bar'
|
11
|
-
|
14
|
+
|
12
15
|
xattr['user.foo'] #=> 'bar'
|
13
16
|
xattr.list #=> ["user.foo"]
|
14
|
-
|
17
|
+
|
15
18
|
xattr.each { |key, value| ... }
|
16
19
|
xattr.as_json #=> {"user.foo" => "bar"}
|
17
20
|
|
18
|
-
TODO
|
19
|
-
----
|
20
|
-
|
21
|
-
* Handle symlinks
|
22
|
-
|
23
21
|
|
24
22
|
Note on Patches/Pull Requests
|
25
23
|
-----------------------------
|
data/Rakefile
CHANGED
data/ffi-xattr.gemspec
CHANGED
@@ -14,8 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = "ffi-xattr"
|
16
16
|
|
17
|
-
|
17
|
+
|
18
18
|
s.add_dependency "ffi"
|
19
|
+
s.add_development_dependency "rspec", "~> 2.5"
|
20
|
+
s.add_development_dependency "rake", "~> 0.9.2"
|
19
21
|
|
20
22
|
s.files = `git ls-files`.split("\n")
|
21
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/ffi-xattr/darwin_lib.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Xattr
|
1
|
+
class Xattr # :nodoc: all
|
2
2
|
module Lib
|
3
3
|
extend FFI::Library
|
4
4
|
|
@@ -9,32 +9,39 @@ class Xattr
|
|
9
9
|
attach_function :setxattr, [:string, :string, :pointer, :size_t, :uint, :int], :int
|
10
10
|
attach_function :removexattr, [:string, :string, :int], :int
|
11
11
|
|
12
|
+
XATTR_NOFOLLOW = 0x0001
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
class << self
|
15
|
+
def list(path, no_follow)
|
16
|
+
options = no_follow ? XATTR_NOFOLLOW : 0
|
17
|
+
size = listxattr(path, nil, 0, options)
|
18
|
+
res_ptr = FFI::MemoryPointer.new(:pointer, size)
|
19
|
+
listxattr(path, res_ptr, size, options)
|
17
20
|
|
18
|
-
|
19
|
-
|
21
|
+
res_ptr.read_string(size).split("\000")
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
def get(path, no_follow, key)
|
25
|
+
options = no_follow ? XATTR_NOFOLLOW : 0
|
26
|
+
size = getxattr(path, key, nil, 0, 0, options)
|
27
|
+
return unless size > 0
|
24
28
|
|
25
|
-
|
26
|
-
|
29
|
+
str_ptr = FFI::MemoryPointer.new(:char, size)
|
30
|
+
getxattr(path, key, str_ptr, size, 0, options)
|
27
31
|
|
28
|
-
|
29
|
-
|
32
|
+
str_ptr.read_string
|
33
|
+
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
|
35
|
+
def set(path, no_follow, key, value)
|
36
|
+
options = no_follow ? XATTR_NOFOLLOW : 0
|
37
|
+
Error.check setxattr(path, key, value, value.bytesize, 0, options)
|
38
|
+
end
|
34
39
|
|
35
|
-
|
36
|
-
|
40
|
+
def remove(path, no_follow, key)
|
41
|
+
options = no_follow ? XATTR_NOFOLLOW : 0
|
42
|
+
Error.check removexattr(path, key, options)
|
43
|
+
end
|
37
44
|
end
|
38
45
|
|
39
46
|
end
|
40
|
-
end
|
47
|
+
end
|
data/lib/ffi-xattr/error.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Xattr
|
1
|
+
class Xattr # :nodoc: all
|
2
2
|
module Error
|
3
3
|
extend FFI::Library
|
4
4
|
|
@@ -6,15 +6,17 @@ class Xattr
|
|
6
6
|
|
7
7
|
attach_function :strerror_r, [:int, :pointer, :size_t], :int
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
class << self
|
10
|
+
def last
|
11
|
+
ptr = FFI::MemoryPointer.new(:char, 256)
|
12
|
+
strerror_r(FFI.errno, ptr, 256)
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
ptr.read_string
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
def check(int)
|
18
|
+
raise last if int != 0
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
|
-
end
|
22
|
+
end
|
data/lib/ffi-xattr/linux_lib.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Xattr
|
1
|
+
class Xattr # :nodoc: all
|
2
2
|
module Lib
|
3
3
|
extend FFI::Library
|
4
4
|
|
@@ -11,31 +11,42 @@ class Xattr
|
|
11
11
|
attach_function :getxattr, [:string, :string, :pointer, :size_t], :int
|
12
12
|
attach_function :removexattr, [:string, :string], :int
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
14
|
+
attach_function :llistxattr, [:string, :pointer, :size_t], :size_t
|
15
|
+
attach_function :lsetxattr, [:string, :string, :pointer, :size_t, :int], :int
|
16
|
+
attach_function :lgetxattr, [:string, :string, :pointer, :size_t], :int
|
17
|
+
attach_function :lremovexattr, [:string, :string], :int
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def list(path, no_follow)
|
21
|
+
method = no_follow ? :llistxattr : :listxattr
|
22
|
+
size = send(method, path, nil, 0)
|
23
|
+
res_ptr = FFI::MemoryPointer.new(:pointer, size)
|
24
|
+
send(method, path, res_ptr, size)
|
25
|
+
|
26
|
+
res_ptr.read_string(size).split("\000")
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(path, no_follow, key)
|
30
|
+
method = no_follow ? :lgetxattr : :getxattr
|
31
|
+
size = send(method, path, key, nil, 0)
|
32
|
+
return unless size > 0
|
33
|
+
|
34
|
+
str_ptr = FFI::MemoryPointer.new(:char, size)
|
35
|
+
send(method, path, key, str_ptr, size)
|
36
|
+
|
37
|
+
str_ptr.read_string
|
38
|
+
end
|
39
|
+
|
40
|
+
def set(path, no_follow, key, value)
|
41
|
+
method = no_follow ? :lsetxattr : :setxattr
|
42
|
+
Error.check send(method, path, key, value, value.bytesize, 0)
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove(path, no_follow, key)
|
46
|
+
method = no_follow ? :lremovexattr : :removexattr
|
47
|
+
Error.check send(method, path, key)
|
48
|
+
end
|
38
49
|
end
|
39
50
|
|
40
51
|
end
|
41
|
-
end
|
52
|
+
end
|
data/lib/ffi-xattr/version.rb
CHANGED
data/lib/ffi-xattr.rb
CHANGED
@@ -14,35 +14,44 @@ end
|
|
14
14
|
class Xattr
|
15
15
|
include Enumerable
|
16
16
|
|
17
|
-
|
17
|
+
# Create a new Xattr instance with path.
|
18
|
+
# Use <tt>:no_follow => true</tt> in options to work on symlink itself instead of following it.
|
19
|
+
def initialize(path, options = {})
|
18
20
|
raise Errno::ENOENT, path unless File.exist?(path)
|
19
21
|
@path = path
|
22
|
+
@no_follow = !!options[:no_follow]
|
20
23
|
end
|
21
24
|
|
25
|
+
# List extended attribute names
|
22
26
|
def list
|
23
|
-
Lib.list @path
|
27
|
+
Lib.list @path, @no_follow
|
24
28
|
end
|
25
29
|
|
30
|
+
# Get an extended attribute value
|
26
31
|
def get(key)
|
27
|
-
Lib.get @path, key.to_s
|
32
|
+
Lib.get @path, @no_follow, key.to_s
|
28
33
|
end
|
29
34
|
alias_method :[], :get
|
30
35
|
|
36
|
+
# Set an extended attribute value
|
31
37
|
def set(key, value)
|
32
|
-
Lib.set @path, key.to_s, value.to_s
|
38
|
+
Lib.set @path, @no_follow, key.to_s, value.to_s
|
33
39
|
end
|
34
40
|
alias_method :[]=, :set
|
35
41
|
|
42
|
+
# Remove an extended attribute value
|
36
43
|
def remove(key)
|
37
|
-
Lib.remove @path, key.to_s
|
44
|
+
Lib.remove @path, @no_follow, key.to_s
|
38
45
|
end
|
39
46
|
|
47
|
+
# Iterates over pairs of extended attribute names and values
|
40
48
|
def each(&blk)
|
41
49
|
list.each do |key|
|
42
50
|
yield key, get(key)
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
54
|
+
# Returns hash of extended attributes
|
46
55
|
def as_json(*args)
|
47
56
|
res = {}
|
48
57
|
each { |k,v| res[k] = v }
|
@@ -51,5 +60,3 @@ class Xattr
|
|
51
60
|
end
|
52
61
|
|
53
62
|
end
|
54
|
-
|
55
|
-
|
data/spec/xattr_spec.rb
CHANGED
@@ -35,6 +35,10 @@ describe Xattr do
|
|
35
35
|
xattr.list.should == []
|
36
36
|
end
|
37
37
|
|
38
|
+
it "raises error when tries to remove inexistent attribute" do
|
39
|
+
lambda { xattr.remove("inexisting") }.should raise_error
|
40
|
+
end
|
41
|
+
|
38
42
|
it "returns nil if the attribute is not set" do
|
39
43
|
xattr.get("hello").should be_nil
|
40
44
|
end
|
@@ -71,4 +75,66 @@ describe Xattr do
|
|
71
75
|
lambda { Xattr.new("no-such-file") }.should raise_error(Errno::ENOENT)
|
72
76
|
end
|
73
77
|
|
78
|
+
describe "respecting :no_follow option" do
|
79
|
+
let(:link) { "link.txt" }
|
80
|
+
let(:xattr_f) { Xattr.new(link, :no_follow => false) }
|
81
|
+
let(:xattr_n) { Xattr.new(link, :no_follow => true) }
|
82
|
+
|
83
|
+
before { File.symlink(path, link) }
|
84
|
+
after { File.delete(link) }
|
85
|
+
|
86
|
+
case RUBY_PLATFORM
|
87
|
+
when /linux/
|
88
|
+
# http://linux.die.net/man/5/attr
|
89
|
+
it "should allow getting extended attributes on any type" do
|
90
|
+
xattr['user.a']
|
91
|
+
xattr_f['user.b']
|
92
|
+
xattr_n['user.c']
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should fail setting extended attributes on symlink" do
|
96
|
+
lambda { xattr['user.a'] = 'foo' }.should_not raise_error
|
97
|
+
lambda { xattr_f['user.b'] = 'bar' }.should_not raise_error
|
98
|
+
lambda { xattr_n['user.c'] = 'baz' }.should raise_error
|
99
|
+
end
|
100
|
+
when /darwin|bsd/
|
101
|
+
it "should set and get attributes" do
|
102
|
+
xattr['user.a'] = 'foo'
|
103
|
+
xattr_f['user.b'] = 'bar'
|
104
|
+
xattr_n['user.c'] = 'baz'
|
105
|
+
|
106
|
+
xattr.list.sort.should == %w[user.a user.b]
|
107
|
+
xattr_f.list.sort.should == %w[user.a user.b]
|
108
|
+
xattr_n.list.sort.should == %w[user.c]
|
109
|
+
|
110
|
+
xattr['user.a'].should == 'foo'
|
111
|
+
xattr['user.b'].should == 'bar'
|
112
|
+
xattr['user.c'].should be_nil
|
113
|
+
xattr_f['user.a'].should == 'foo'
|
114
|
+
xattr_f['user.b'].should == 'bar'
|
115
|
+
xattr_f['user.c'].should be_nil
|
116
|
+
xattr_n['user.a'].should be_nil
|
117
|
+
xattr_n['user.b'].should be_nil
|
118
|
+
xattr_n['user.c'].should == 'baz'
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should remove attributes" do
|
122
|
+
xattr['user.a'] = 'foo'
|
123
|
+
xattr_f['user.b'] = 'bar'
|
124
|
+
xattr_n['user.c'] = 'baz'
|
125
|
+
xattr_n['user.d'] = 'ban'
|
126
|
+
|
127
|
+
xattr.list.sort.should == %w[user.a user.b]
|
128
|
+
xattr_f.list.sort.should == %w[user.a user.b]
|
129
|
+
xattr_n.list.sort.should == %w[user.c user.d]
|
130
|
+
|
131
|
+
xattr_f.remove('user.a')
|
132
|
+
xattr_n.remove('user.c')
|
133
|
+
|
134
|
+
xattr.list.sort.should == %w[user.b]
|
135
|
+
xattr_f.list.sort.should == %w[user.b]
|
136
|
+
xattr_n.list.sort.should == %w[user.d]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
74
140
|
end
|
metadata
CHANGED
@@ -1,46 +1,79 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-xattr
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Jari Bakken
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
|
18
|
+
date: 2011-11-15 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
type: :runtime
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
23
|
none: false
|
18
|
-
requirements:
|
19
|
-
- -
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
|
22
|
-
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
23
31
|
prerelease: false
|
24
|
-
version_requirements: *2164580140
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
32
|
name: ffi
|
27
|
-
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
type: :development
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
37
|
none: false
|
29
|
-
requirements:
|
30
|
-
- -
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
|
33
|
-
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
hash: 9
|
42
|
+
segments:
|
43
|
+
- 2
|
44
|
+
- 5
|
45
|
+
version: "2.5"
|
46
|
+
prerelease: false
|
47
|
+
name: rspec
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
type: :development
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 63
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
- 9
|
60
|
+
- 2
|
61
|
+
version: 0.9.2
|
34
62
|
prerelease: false
|
35
|
-
|
63
|
+
name: rake
|
64
|
+
version_requirements: *id003
|
36
65
|
description: Manipulate extended file attributes
|
37
|
-
email:
|
66
|
+
email:
|
38
67
|
- jari.bakken@gmail.com
|
39
68
|
executables: []
|
69
|
+
|
40
70
|
extensions: []
|
71
|
+
|
41
72
|
extra_rdoc_files: []
|
42
|
-
|
73
|
+
|
74
|
+
files:
|
43
75
|
- .gitignore
|
76
|
+
- .travis.yml
|
44
77
|
- Gemfile
|
45
78
|
- LICENSE
|
46
79
|
- README.md
|
@@ -54,27 +87,36 @@ files:
|
|
54
87
|
- spec/xattr_spec.rb
|
55
88
|
homepage: http://github.com/jarib/ffi-xattr
|
56
89
|
licenses: []
|
90
|
+
|
57
91
|
post_install_message:
|
58
92
|
rdoc_options: []
|
59
|
-
|
93
|
+
|
94
|
+
require_paths:
|
60
95
|
- lib
|
61
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
97
|
none: false
|
63
|
-
requirements:
|
64
|
-
- -
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
|
67
|
-
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
106
|
none: false
|
69
|
-
requirements:
|
70
|
-
- -
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
73
114
|
requirements: []
|
115
|
+
|
74
116
|
rubyforge_project: ffi-xattr
|
75
117
|
rubygems_version: 1.8.10
|
76
118
|
signing_key:
|
77
119
|
specification_version: 3
|
78
120
|
summary: Manipulate extended file attributes
|
79
|
-
test_files:
|
121
|
+
test_files:
|
80
122
|
- spec/xattr_spec.rb
|