extattr 0.1 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/HISTORY.ja.md +49 -0
- data/{LICENSE.txt → LICENSE.md} +5 -0
- data/QUICKREF.ja.md +112 -0
- data/README.md +84 -0
- data/Rakefile +212 -0
- data/ext/extattr-extattr.h +192 -0
- data/ext/extattr-windows.h +724 -0
- data/ext/extattr-xattr.h +229 -0
- data/ext/extattr.c +393 -206
- data/ext/extconf.rb +16 -12
- data/gemstub.rb +22 -0
- data/lib/extattr.rb +274 -0
- data/test/test_extattr.rb +75 -0
- metadata +70 -37
- data/README.txt +0 -53
- data/ext/extattr.bsd +0 -186
- data/ext/extattr.linux +0 -209
- data/ext/extattr.windows +0 -407
- data/rspecs/extattr.rb +0 -53
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0a1d94f6586158eb3abf46fb3fc8d43edd251763379f32e57f77ebfaa1db0a6f
|
4
|
+
data.tar.gz: 80e8c90ee1e866018f7ddc06d621f733f33276b5beaeac8cd9687da3a086a9a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ccd9f917160b92b4cc52e02d56505b5824750a73442b8bad7d71041e3e5bd3f0b81dc2a93b5db14312093df65e12fca78085b7f0fc91c2263c53571821ff5679
|
7
|
+
data.tar.gz: 0b68f33f665fc50938567a64f8adb3ecdec402c699b3bc26e143a41a73ffd489c6b5d6ffdfc5ee813a82f26bef9ff9b1df4e3850ff2bb853274525fefcb86d74
|
data/HISTORY.ja.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# extattr-0.4
|
2
|
+
|
3
|
+
- Ruby 3 の `Ractor` への対応 (thanks @okeeblow, https://github.com/dearblue/ruby-extattr/pull/1)
|
4
|
+
- `bin/extattr` コマンドラインプログラムを削除
|
5
|
+
|
6
|
+
まだ小さな不具合があり、調整が必要です。
|
7
|
+
独立した gem `extattr-cli` として提供することを計画しています。
|
8
|
+
|
9
|
+
|
10
|
+
# extattr-0.3
|
11
|
+
|
12
|
+
extattr-0.2 との互換性はありません。
|
13
|
+
|
14
|
+
- `ExtAttr` モジュールを追加して実装をそちらに移動
|
15
|
+
- `File` クラスに対するメソッドの追加は、リファインメント機能によって拡張されます。
|
16
|
+
```ruby
|
17
|
+
using ExtAttr
|
18
|
+
```
|
19
|
+
- `File::EXTATTR_VERSION` 定数は冗長と判断し削除しました。
|
20
|
+
- `ExtAttr::Accessor` クラスの追加
|
21
|
+
- 拡張属性の操作に特化したオブジェクトを扱えるようになりました。
|
22
|
+
- `bin/extattr` コマンドラインプログラムの追加
|
23
|
+
- mingw でライブラリを構築する時 C 実行時ライブラリを静的リンクするように変更
|
24
|
+
|
25
|
+
# extattr-0.2
|
26
|
+
|
27
|
+
* セーフレベルに関する改善
|
28
|
+
* `$SAFE` と汚染状態を確認するようになりました
|
29
|
+
* 汚染状態を伝播させるようになりました
|
30
|
+
* バージョン情報と実装 API に関する情報の取得
|
31
|
+
* `File::EXTATTR_VERSION` 定数によって、バージョン情報が取得できるようになりました
|
32
|
+
* `File::EXTATTR_IMPLEMENT` 定数によって、実装に関する情報が取得できるようになりました
|
33
|
+
* 機能の改善
|
34
|
+
* `File.extattr_each` / `File#extattr_each` によって、ファイル拡張属性の名前と値を繰り返し取得できるようになりました
|
35
|
+
* Windows 版に関する改善
|
36
|
+
* `File::EXTATTR_NAMESPACE_SYSTEM` によって、本来の拡張ファイル属性の操作が行えるようになりました
|
37
|
+
(NtQueryEaFile / NtSetEaFile)
|
38
|
+
|
39
|
+
# extattr-0.1.2
|
40
|
+
|
41
|
+
# extattr-0.1.1
|
42
|
+
|
43
|
+
# extattr-0.1
|
44
|
+
|
45
|
+
はじめてのりりーす
|
46
|
+
|
47
|
+
* 拡張ファイル属性の一覧、取得、設定、削除を行うことが出来ます
|
48
|
+
* **セキュリティリスクあり**: `$SAFE` の確認や汚染状態の伝播を行ないません
|
49
|
+
* Windows 版では、NTFS ADS に対する操作となります。`File::EXTATTR_NAMESPACE_USER` のみが有効です
|
data/{LICENSE.txt → LICENSE.md}
RENAMED
data/QUICKREF.ja.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Quick Reference
|
2
|
+
|
3
|
+
メソッド名に『!』がついているものはシンボリックリンクに対する操作となります。
|
4
|
+
|
5
|
+
キーワード引数の `namespace` を与えると、拡張属性の名前空間を指定できます。
|
6
|
+
|
7
|
+
与えられる値:
|
8
|
+
|
9
|
+
- `ExtAttr::USER`
|
10
|
+
- `ExtAttr::SYSTEM`
|
11
|
+
- `user` 又は `system` を文字列かシンボルで (大文字小文字は区別されない)
|
12
|
+
- `nil` (`ExtAttr::USER` と等価)
|
13
|
+
|
14
|
+
規定値は `ExtAttr::USER` です。
|
15
|
+
|
16
|
+
|
17
|
+
## モジュール `ExtAttr`
|
18
|
+
|
19
|
+
- `ExtAttr.list(path, namespace) -> array`
|
20
|
+
- `ExtAttr.list!(path, namespace) -> array`
|
21
|
+
- `ExtAttr.size(path, namespace, name) -> integer`
|
22
|
+
- `ExtAttr.size!(path, namespace, name) -> integer`
|
23
|
+
- `ExtAttr.get(path, namespace, name) -> string`
|
24
|
+
- `ExtAttr.get!(path, namespace, name) -> string`
|
25
|
+
- `ExtAttr.set(path, namespace, name, value) -> nil`
|
26
|
+
- `ExtAttr.set!(path, namespace, name, value) -> nil`
|
27
|
+
- `ExtAttr.delete(path, namespace, name) -> nil`
|
28
|
+
- `ExtAttr.delete!(path, namespace, name) -> nil`
|
29
|
+
- `ExtAttr.open(path) -> a ExtAttr::Accessor instance`
|
30
|
+
- `ExtAttr.open(path) { |ea| ... } -> returned value from yield block`
|
31
|
+
- `ExtAttr.each(path, namespace) -> an ExtAttr::Accessor instance`
|
32
|
+
- `ExtAttr.each(path, namespace = ExtAttr::USER) -> an enumerator instance`
|
33
|
+
- `ExtAttr.each(path, namespace = ExtAttr::USER) { |name, data| ... } -> path`
|
34
|
+
- `ExtAttr.each!(path, namespace = ExtAttr::USER) -> an enumerator instance`
|
35
|
+
- `ExtAttr.each!(path, namespace = ExtAttr::USER) { |name, data| ... } -> path`
|
36
|
+
|
37
|
+
|
38
|
+
## クラス `ExtAttr::Accessor`
|
39
|
+
|
40
|
+
- `ExtAttr::Accessor#each(namespace: ExtAttr::USER) -> an enumerator instance`
|
41
|
+
- `ExtAttr::Accessor#each(namespace: ExtAttr::USER) { |name, data| ... } -> path`
|
42
|
+
- `ExtAttr::Accessor#list(namespace: ExtAttr::USER) -> array`
|
43
|
+
- `ExtAttr::Accessor#size(name, namespace: ExtAttr::USER) -> integer`
|
44
|
+
- `ExtAttr::Accessor#get(name, namespace: ExtAttr::USER) -> string`
|
45
|
+
- `ExtAttr::Accessor#set(name, data, namespace: ExtAttr::USER) -> nil`
|
46
|
+
- `ExtAttr::Accessor#delete(name, namespace: ExtAttr::USER) -> nil`
|
47
|
+
|
48
|
+
|
49
|
+
## リファインメント `using ExtAttr`
|
50
|
+
|
51
|
+
リファインメント機能を使うことにより、`File` が拡張されます。
|
52
|
+
|
53
|
+
### 拡張属性オブジェクトを生成する
|
54
|
+
|
55
|
+
```ruby:ruby
|
56
|
+
File.extattr(path) -> an ExtAttr::Accessor instance
|
57
|
+
File#extattr -> an ExtAttr::Accessor instance
|
58
|
+
```
|
59
|
+
|
60
|
+
### 拡張属性の属性名を取得
|
61
|
+
|
62
|
+
```ruby:ruby
|
63
|
+
File.extattr_list(path, namespace: ExtAttr::USER) -> array
|
64
|
+
File.extattr_list(path, namespace: ExtAttr::USER) { |name| ... } -> nil
|
65
|
+
File.extattr_list!(path, namespace: ExtAttr::USER) -> array
|
66
|
+
File.extattr_list!(path, namespace: ExtAttr::USER) { |name| ... } -> nil
|
67
|
+
File#extattr_list(namespace: ExtAttr::USER) -> array
|
68
|
+
File#extattr_list(namespace: ExtAttr::USER) { |name| ... } -> nil
|
69
|
+
```
|
70
|
+
|
71
|
+
### 拡張属性の要素の大きさを取得
|
72
|
+
|
73
|
+
```ruby:ruby
|
74
|
+
File.extattr_size(path, name, namespace: ExtAttr::USER) -> size
|
75
|
+
File.extattr_size!(path, name, namespace: ExtAttr::USER) -> size
|
76
|
+
File#extattr_size(name, namespace: ExtAttr::USER) -> size
|
77
|
+
```
|
78
|
+
|
79
|
+
### 拡張属性の要素を取得
|
80
|
+
|
81
|
+
```ruby:ruby
|
82
|
+
File.extattr_get(path, name, namespace: ExtAttr::USER) -> data (String)
|
83
|
+
File.extattr_get!(path, name, namespace: ExtAttr::USER) -> data (String)
|
84
|
+
File#extattr_get(name, namespace: ExtAttr::USER) -> data (String)
|
85
|
+
```
|
86
|
+
|
87
|
+
### 拡張属性の要素を設定
|
88
|
+
|
89
|
+
```ruby:ruby
|
90
|
+
File.extattr_set(path, name, data, namespace: ExtAttr::USER) -> nil
|
91
|
+
File.extattr_set!(path, name, data, namespace: ExtAttr::USER) -> nil
|
92
|
+
File#extattr_set(name, data, namespace: ExtAttr::USER) -> nil
|
93
|
+
```
|
94
|
+
|
95
|
+
### 拡張属性の要素を削除
|
96
|
+
|
97
|
+
```ruby:ruby
|
98
|
+
File.extattr_delete(path, name, namespace: ExtAttr::USER) -> nil
|
99
|
+
File.extattr_delete!(path, name, namespace: ExtAttr::USER) -> nil
|
100
|
+
File#extattr_delete(name, namespace: ExtAttr::USER) -> nil
|
101
|
+
```
|
102
|
+
|
103
|
+
### 拡張属性の属性名と要素を列挙する
|
104
|
+
|
105
|
+
```ruby:ruby
|
106
|
+
File.extattr_each(path, namespace: ExtAttr::USER) -> Enumerator
|
107
|
+
File.extattr_each(path, namespace: ExtAttr::USER) { |name, data| ... } -> nil
|
108
|
+
File.extattr_each!(path, namespace: ExtAttr::USER) -> Enumerator
|
109
|
+
File.extattr_each!(path, namespace: ExtAttr::USER) { |name, data| ... } -> nil
|
110
|
+
File#extattr_each(namespace: ExtAttr::USER) -> Enumerator
|
111
|
+
File#extattr_each(namespace: ExtAttr::USER) { |name, data| ... } -> file
|
112
|
+
```
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# extattr - filesystem extended attributes manipurator for Ruby
|
2
|
+
|
3
|
+
extattr is filesystem extended attributes manipurator for Ruby on FreeBSD, GNU/Linux and Microsoft Windows.
|
4
|
+
|
5
|
+
- [Quick Reference](QUICKREF.ja.md) (in Japanese)
|
6
|
+
- [HISTORY](HISTORY.ja.md) (in Japanese)
|
7
|
+
|
8
|
+
extattr はファイルシステムの拡張属性を操作するライブラリで、FreeBSD、GNU/Linux、Windows に対応しています。
|
9
|
+
|
10
|
+
サポートされる環境で、統一的なメソッドを提供します。
|
11
|
+
|
12
|
+
実装については、以下のようになっています。
|
13
|
+
|
14
|
+
* FreeBSD: extattr (`extattr_list`, `extattr_get`, `extattr_set`, `extattr_delete`)
|
15
|
+
* GNU/Linux: xattr (`listxattr`, `getxattr`, `setxattr`, `removexattr`)
|
16
|
+
* Microsoft Windows: NTFS ADS (代替データストリーム) / 拡張ファイル属性 (`NtQueryEaFile`, `NtSetEaFile`)
|
17
|
+
|
18
|
+
|
19
|
+
## Tested system
|
20
|
+
|
21
|
+
* PC-BSD/AMD64 10.0
|
22
|
+
* lubuntu 13.10 (i386)
|
23
|
+
* Microsoft Windows XP Professional SP3
|
24
|
+
* Microsoft Windows 7 Professional SP1
|
25
|
+
|
26
|
+
|
27
|
+
## GNU/Linux における特記事項
|
28
|
+
|
29
|
+
* GNU/Linux で利用されている名前空間〈security〉〈trusted〉には未対応です。
|
30
|
+
|
31
|
+
|
32
|
+
## Microsoft Windows における特記事項
|
33
|
+
|
34
|
+
* Windows XP 以降を必要とします。Win2k でも動作するかもしれません (未検証)。<br>
|
35
|
+
Windows 9x シリーズでは `require "extattr"` の段階で例外が発生すると思われます (未検証)。
|
36
|
+
* ``ExtAttr::USER`` は (比較的よく利用される) NTFS ADS に対する操作で、``ExtAttr::SYSTEM`` が本来の (あまり利用されていない) 拡張ファイル属性に対する操作となります。
|
37
|
+
* リパースポイント (ジャンクションやシンボリックリンク) に対する NTFS ADS は要素の取得や設定、削除は出来ません。<br>
|
38
|
+
必ずリンク先に対する操作となります (やり方がわかりません)。
|
39
|
+
* 64 KiB を超える NTFS ADS は取得も設定も出来ません。<br>
|
40
|
+
これは『拡張属性』と捉えた場合、巨大なデータを扱えるべきではないという考えによるためです
|
41
|
+
(本当のところは FreeBSD の拡張属性が最大 64KiB 弱であることが由来です)。
|
42
|
+
* 巨大な NTFS ADS を扱いたい場合は、``File.open`` でファイルとして扱えるので自由に読み書きできます。<br>
|
43
|
+
これは Ruby に限ったことではなく、Windows による仕様です。<br>
|
44
|
+
この場合の与えるファイル名は、``path + ":" + name`` という形になります。
|
45
|
+
|
46
|
+
``` ruby:ruby
|
47
|
+
filepath = "sample.txt"
|
48
|
+
extattrname = "category"
|
49
|
+
ntfs_ads_name = filepath + ":" + extattrname
|
50
|
+
File.open(ntfs_ads_name, "r") do |file|
|
51
|
+
...
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
## 既知のバグ
|
56
|
+
|
57
|
+
* ``extattr_list`` のブロック内で ``extattr_set`` ``extattr_delete`` を行うと正確な列挙がされない場合がある
|
58
|
+
|
59
|
+
解決方法: ``extattr_set`` か ``extattr_delete`` のどちらかを同時に利用したい場合、``extattr_list.each`` を用いてください。
|
60
|
+
|
61
|
+
|
62
|
+
## 参考資料
|
63
|
+
|
64
|
+
* extattr
|
65
|
+
* <https://www.freebsd.org/cgi/man.cgi?query=extattr&sektion=2>
|
66
|
+
* xattr
|
67
|
+
* <https://linuxjm.osdn.jp/html/LDP_man-pages/man2/listxattr.2.html>
|
68
|
+
* windows
|
69
|
+
* <https://msdn.microsoft.com/en-us/library/cc232069.aspx>
|
70
|
+
* <https://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/FILE_INFORMATION_CLASS.html>
|
71
|
+
* <https://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtQueryInformationFile.html>
|
72
|
+
* <https://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtQueryEaFile.html>
|
73
|
+
* <https://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtSetEaFile.html>
|
74
|
+
* FileTest <http://www.zezula.net/en/fstools/filetest.html> <https://github.com/ladislav-zezula/FileTest>
|
75
|
+
|
76
|
+
## Specification
|
77
|
+
|
78
|
+
- package name: [extattr](https://rubygems.org/gems/extattr)
|
79
|
+
- Author: dearblue
|
80
|
+
- Version: 0.4
|
81
|
+
- Product quality: technical preview
|
82
|
+
- License: [2-clause BSD License](LICENSE.md)
|
83
|
+
- Project page: <https://github.com/dearblue/ruby-extattr>
|
84
|
+
- Support Ruby: Ruby 2.5+
|
data/Rakefile
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
|
2
|
+
require "pathname"
|
3
|
+
require "rake/clean"
|
4
|
+
|
5
|
+
docnames = "{README,LICENSE,CHANGELOG,Changelog,HISTORY}"
|
6
|
+
doctypes = "{,.txt,.rd,.rdoc,.md,.markdown}"
|
7
|
+
cexttypes = "{c,C,cc,cxx,cpp,h,H,hh}"
|
8
|
+
|
9
|
+
DOC = FileList["#{docnames}{,.ja}#{doctypes}"] +
|
10
|
+
FileList["{contrib,ext}/**/#{docnames}{,.ja}#{doctypes}"] +
|
11
|
+
FileList["ext/**/*.#{cexttypes}"]
|
12
|
+
EXT = FileList["ext/**/*"]
|
13
|
+
BIN = FileList["bin/*"]
|
14
|
+
LIB = FileList["lib/**/*.rb"]
|
15
|
+
SPEC = FileList["spec/**/*"]
|
16
|
+
TEST = FileList["test/**/*"]
|
17
|
+
EXAMPLE = FileList["examples/**/*"]
|
18
|
+
GEMSTUB_SRC = "gemstub.rb"
|
19
|
+
RAKEFILE = [File.basename(__FILE__), GEMSTUB_SRC]
|
20
|
+
EXTRA = []
|
21
|
+
EXTCONF = FileList["ext/**/extconf.rb"]
|
22
|
+
EXTCONF.reject! { |n| !File.file?(n) }
|
23
|
+
EXTMAP = {}
|
24
|
+
|
25
|
+
load GEMSTUB_SRC
|
26
|
+
|
27
|
+
EXTMAP.dup.each_pair do |dir, name|
|
28
|
+
EXTMAP[Pathname.new(dir).cleanpath.to_s] = Pathname.new(name).cleanpath.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
GEMSTUB.extensions += EXTCONF
|
32
|
+
GEMSTUB.executables += FileList["bin/*"].map { |n| File.basename n }
|
33
|
+
GEMSTUB.executables.sort!
|
34
|
+
|
35
|
+
PACKAGENAME = "#{GEMSTUB.name}-#{GEMSTUB.version}"
|
36
|
+
GEMFILE = "#{PACKAGENAME}.gem"
|
37
|
+
GEMSPEC = "#{PACKAGENAME}.gemspec"
|
38
|
+
|
39
|
+
GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + EXTRA
|
40
|
+
GEMSTUB.files.sort!
|
41
|
+
if GEMSTUB.rdoc_options.nil? || GEMSTUB.rdoc_options.empty?
|
42
|
+
readme = %W(.md .markdown .rd .rdoc .txt #{""}).map { |ext| "README#{ext}" }.find { |m| DOC.find { |n| n == m } }
|
43
|
+
GEMSTUB.rdoc_options = %w(--charset UTF-8) + (readme ? %W(-m #{readme}) : [])
|
44
|
+
end
|
45
|
+
GEMSTUB.extra_rdoc_files += DOC + LIB + EXT.reject { |n| n.include?("/externals/") || !%w(.h .hh .c .cc .cpp .cxx).include?(File.extname(n)) }
|
46
|
+
GEMSTUB.extra_rdoc_files.sort!
|
47
|
+
|
48
|
+
GEMSTUB_TRYOUT = GEMSTUB.dup
|
49
|
+
GEMSTUB_TRYOUT.version = "#{GEMSTUB.version}#{Time.now.strftime(".TRYOUT.%Y%m%d.%H%M%S")}"
|
50
|
+
PACKAGENAME_TRYOUT = "#{GEMSTUB.name}-#{GEMSTUB_TRYOUT.version}"
|
51
|
+
GEMFILE_TRYOUT = "#{PACKAGENAME_TRYOUT}.gem"
|
52
|
+
GEMSPEC_TRYOUT = "#{PACKAGENAME_TRYOUT}.gemspec"
|
53
|
+
|
54
|
+
CLEAN << GEMSPEC << GEMSPEC_TRYOUT
|
55
|
+
CLOBBER << GEMFILE
|
56
|
+
|
57
|
+
task :default => :tryout do
|
58
|
+
$stderr.puts <<-EOS
|
59
|
+
#{__FILE__}:#{__LINE__}:
|
60
|
+
\ttype ``rake release'' to build release package.
|
61
|
+
EOS
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "build tryout package"
|
65
|
+
task :tryout
|
66
|
+
|
67
|
+
desc "build release package"
|
68
|
+
task :release => :all
|
69
|
+
|
70
|
+
unless EXTCONF.empty?
|
71
|
+
RUBYSET ||= (ENV["RUBYSET"] || "").split(",")
|
72
|
+
|
73
|
+
if RUBYSET.nil? || RUBYSET.empty?
|
74
|
+
$stderr.puts <<-EOS
|
75
|
+
#{__FILE__}:
|
76
|
+
|
|
77
|
+
| If you want binary gem package, launch rake with ``RUBYSET`` enviroment
|
78
|
+
| variable for set ruby interpreters by comma separated.
|
79
|
+
|
|
80
|
+
| e.g.) $ rake RUBYSET=ruby
|
81
|
+
| or) $ rake RUBYSET=ruby21,ruby22,ruby23
|
82
|
+
|
|
83
|
+
EOS
|
84
|
+
else
|
85
|
+
platforms = RUBYSET.map { |ruby| `#{ruby} --disable-gems -e "puts RUBY_PLATFORM"`.chomp }
|
86
|
+
platforms1 = platforms.uniq
|
87
|
+
unless platforms1.size == 1 && !platforms1[0].empty?
|
88
|
+
abort <<-EOS
|
89
|
+
#{__FILE__}:#{__LINE__}: different platforms:
|
90
|
+
#{RUBYSET.zip(platforms).map { |ruby, platform| "%24s => %s" % [ruby, platform] }.join("\n")}
|
91
|
+
ABORTED.
|
92
|
+
EOS
|
93
|
+
end
|
94
|
+
PLATFORM = platforms1[0]
|
95
|
+
|
96
|
+
RUBY_VERSIONS = RUBYSET.map do |ruby|
|
97
|
+
ver = `#{ruby} --disable-gems -e "puts RUBY_VERSION"`.slice(/\d+\.\d+/)
|
98
|
+
raise "failed ruby checking - ``#{ruby}''" unless $?.success?
|
99
|
+
[ver, ruby]
|
100
|
+
end
|
101
|
+
|
102
|
+
SOFILES_SET = RUBY_VERSIONS.map { |(ver, ruby)|
|
103
|
+
EXTCONF.map { |extconf|
|
104
|
+
extdir = Pathname.new(extconf).cleanpath.dirname.to_s
|
105
|
+
case
|
106
|
+
when soname = EXTMAP[extdir.sub(/^ext\//i, "")]
|
107
|
+
soname = soname.sub(/\.so$/i, "")
|
108
|
+
when extdir == "ext" || extdir == "."
|
109
|
+
soname = GEMSTUB.name
|
110
|
+
else
|
111
|
+
soname = File.basename(extdir)
|
112
|
+
end
|
113
|
+
|
114
|
+
[ruby, File.join("lib", "#{soname.sub(/(?<=\/)|^(?!.*\/)/, "#{ver}/")}.so"), extconf]
|
115
|
+
}
|
116
|
+
}.flatten(1)
|
117
|
+
SOFILES = SOFILES_SET.map { |(ruby, sopath, extconf)| sopath }
|
118
|
+
|
119
|
+
GEMSTUB_NATIVE = GEMSTUB.dup
|
120
|
+
GEMSTUB_NATIVE.files += SOFILES
|
121
|
+
GEMSTUB_NATIVE.platform = Gem::Platform.new(PLATFORM).to_s
|
122
|
+
GEMSTUB_NATIVE.extensions.clear
|
123
|
+
GEMFILE_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.version}-#{GEMSTUB_NATIVE.platform}.gem"
|
124
|
+
GEMSPEC_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.platform}.gemspec"
|
125
|
+
|
126
|
+
task :all => ["native-gem", GEMFILE]
|
127
|
+
|
128
|
+
desc "build binary gem package"
|
129
|
+
task "native-gem" => GEMFILE_NATIVE
|
130
|
+
|
131
|
+
desc "generate binary gemspec"
|
132
|
+
task "native-gemspec" => GEMSPEC_NATIVE
|
133
|
+
|
134
|
+
file GEMFILE_NATIVE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + SOFILES + RAKEFILE + [GEMSPEC_NATIVE] do
|
135
|
+
sh "gem build #{GEMSPEC_NATIVE}"
|
136
|
+
end
|
137
|
+
|
138
|
+
file GEMSPEC_NATIVE => RAKEFILE do
|
139
|
+
File.write(GEMSPEC_NATIVE, GEMSTUB_NATIVE.to_ruby, mode: "wb")
|
140
|
+
end
|
141
|
+
|
142
|
+
desc "build c-extension libraries"
|
143
|
+
task "sofiles" => SOFILES
|
144
|
+
|
145
|
+
SOFILES_SET.each do |(ruby, soname, extconf)|
|
146
|
+
sodir = File.dirname(soname)
|
147
|
+
makefile = File.join(sodir, "Makefile")
|
148
|
+
|
149
|
+
CLEAN << GEMSPEC_NATIVE << sodir
|
150
|
+
CLOBBER << GEMFILE_NATIVE
|
151
|
+
|
152
|
+
directory sodir
|
153
|
+
|
154
|
+
desc "generate Makefile for binary extension library"
|
155
|
+
file makefile => [sodir, extconf] do
|
156
|
+
rel_extconf = Pathname.new(extconf).relative_path_from(Pathname.new(sodir)).to_s
|
157
|
+
cd sodir do
|
158
|
+
sh *%W"#{ruby} #{rel_extconf} --ruby=#{ruby} #{ENV["EXTCONF"]}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
desc "build binary extension library"
|
163
|
+
file soname => [makefile] + EXT do
|
164
|
+
cd sodir do
|
165
|
+
sh "make"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
task :all => GEMFILE
|
174
|
+
task :tryout => GEMFILE_TRYOUT
|
175
|
+
|
176
|
+
desc "generate local rdoc"
|
177
|
+
task :rdoc => DOC + LIB do
|
178
|
+
sh *(%w(rdoc) + GEMSTUB.rdoc_options + DOC + LIB)
|
179
|
+
end
|
180
|
+
|
181
|
+
desc "launch rspec"
|
182
|
+
task rspec: :all do
|
183
|
+
sh "rspec"
|
184
|
+
end
|
185
|
+
|
186
|
+
desc "build gem package"
|
187
|
+
task gem: GEMFILE
|
188
|
+
|
189
|
+
desc "generate gemspec"
|
190
|
+
task gemspec: GEMSPEC
|
191
|
+
|
192
|
+
desc "print package name"
|
193
|
+
task "package-name" do
|
194
|
+
puts PACKAGENAME
|
195
|
+
end
|
196
|
+
|
197
|
+
file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + [GEMSPEC] do
|
198
|
+
sh "gem build #{GEMSPEC}"
|
199
|
+
end
|
200
|
+
|
201
|
+
file GEMFILE_TRYOUT => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + [GEMSPEC_TRYOUT] do
|
202
|
+
#file GEMFILE_TRYOUT do
|
203
|
+
sh "gem build #{GEMSPEC_TRYOUT}"
|
204
|
+
end
|
205
|
+
|
206
|
+
file GEMSPEC => RAKEFILE do
|
207
|
+
File.write(GEMSPEC, GEMSTUB.to_ruby, mode: "wb")
|
208
|
+
end
|
209
|
+
|
210
|
+
file GEMSPEC_TRYOUT => RAKEFILE do
|
211
|
+
File.write(GEMSPEC_TRYOUT, GEMSTUB_TRYOUT.to_ruby, mode: "wb")
|
212
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
#include <sys/types.h>
|
2
|
+
#include <sys/extattr.h>
|
3
|
+
|
4
|
+
|
5
|
+
static void
|
6
|
+
extattr_list_name(const char list[], size_t size, VALUE infection_source, void (*func)(void *, VALUE), void *userdata)
|
7
|
+
{
|
8
|
+
// Each list entry consists of a single byte containing the length of
|
9
|
+
// the attribute name, followed by the attribute name.
|
10
|
+
// The attribute name is not terminated by ASCII 0 (nul).
|
11
|
+
const char *ptr = list;
|
12
|
+
const char *end = list + size;
|
13
|
+
|
14
|
+
while (ptr < end) {
|
15
|
+
size_t len = (uint8_t)*ptr ++;
|
16
|
+
if (ptr + len > end) { return; }
|
17
|
+
VALUE v = rb_str_new(ptr, len);
|
18
|
+
OBJ_INFECT(v, infection_source);
|
19
|
+
func(userdata, v);
|
20
|
+
ptr += len;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
static int
|
25
|
+
get_extattr_list_size(ssize_t (*extattr_list)(), intptr_t d, VALUE filesrc, int namespace1)
|
26
|
+
{
|
27
|
+
int size = extattr_list(d, namespace1, NULL, 0);
|
28
|
+
if (size < 0) { aux_sys_fail(filesrc, "extattr_list"); }
|
29
|
+
return size;
|
30
|
+
}
|
31
|
+
|
32
|
+
static VALUE
|
33
|
+
extattr_list_common(ssize_t (*extattr_list)(), intptr_t d, VALUE filesrc, int namespace1)
|
34
|
+
{
|
35
|
+
size_t size = get_extattr_list_size(extattr_list, d, filesrc, namespace1);
|
36
|
+
VALUE buf;
|
37
|
+
char *ptr = ALLOCV(buf, size);
|
38
|
+
|
39
|
+
ssize_t size1 = extattr_list(d, namespace1, ptr, size);
|
40
|
+
if (size1 < 0) { aux_sys_fail(filesrc, "extattr_list"); }
|
41
|
+
|
42
|
+
VALUE list = Qnil;
|
43
|
+
if (rb_block_given_p()) {
|
44
|
+
extattr_list_name(ptr, size1, filesrc,
|
45
|
+
(void (*)(void *, VALUE))rb_yield_values, (void *)(1));
|
46
|
+
} else {
|
47
|
+
list = rb_ary_new();
|
48
|
+
OBJ_INFECT(list, filesrc);
|
49
|
+
extattr_list_name(ptr, size1, filesrc,
|
50
|
+
(void (*)(void *, VALUE))rb_ary_push, (void *)list);
|
51
|
+
}
|
52
|
+
ALLOCV_END(buf);
|
53
|
+
|
54
|
+
return list;
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE
|
58
|
+
file_extattr_list_main(VALUE file, int fd, int namespace1)
|
59
|
+
{
|
60
|
+
return extattr_list_common(extattr_list_fd, fd, file, namespace1);
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE
|
64
|
+
file_s_extattr_list_main(VALUE path, int namespace1)
|
65
|
+
{
|
66
|
+
return extattr_list_common(extattr_list_file, (intptr_t)StringValueCStr(path), path, namespace1);
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE
|
70
|
+
file_s_extattr_list_link_main(VALUE path, int namespace1)
|
71
|
+
{
|
72
|
+
return extattr_list_common(extattr_list_link, (intptr_t)StringValueCStr(path), path, namespace1);
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
static VALUE
|
77
|
+
extattr_size_common(ssize_t (*extattr_get)(), intptr_t d, int namespace1, VALUE name)
|
78
|
+
{
|
79
|
+
ssize_t size = extattr_get(d, namespace1, StringValueCStr(name), NULL, 0);
|
80
|
+
if (size < 0) { rb_sys_fail("extattr_get call error"); }
|
81
|
+
return SIZET2NUM(size);
|
82
|
+
}
|
83
|
+
|
84
|
+
static VALUE
|
85
|
+
file_extattr_size_main(VALUE file, int fd, int namespace1, VALUE name)
|
86
|
+
{
|
87
|
+
return extattr_size_common(extattr_get_fd, fd, namespace1, name);
|
88
|
+
}
|
89
|
+
|
90
|
+
static VALUE
|
91
|
+
file_s_extattr_size_main(VALUE path, int namespace1, VALUE name)
|
92
|
+
{
|
93
|
+
return extattr_size_common(extattr_get_file, (intptr_t)StringValueCStr(path), namespace1, name);
|
94
|
+
}
|
95
|
+
|
96
|
+
static VALUE
|
97
|
+
file_s_extattr_size_link_main(VALUE path, int namespace1, VALUE name)
|
98
|
+
{
|
99
|
+
return extattr_size_common(extattr_get_link, (intptr_t)StringValueCStr(path), namespace1, name);
|
100
|
+
}
|
101
|
+
|
102
|
+
|
103
|
+
static VALUE
|
104
|
+
extattr_get_common(ssize_t (*extattr_get)(), intptr_t d, VALUE path, int namespace1, VALUE name)
|
105
|
+
{
|
106
|
+
ssize_t size = extattr_get(d, namespace1, StringValueCStr(name), NULL, 0);
|
107
|
+
if (size < 0) { rb_sys_fail(StringValueCStr(path)); }
|
108
|
+
VALUE buf = rb_str_buf_new(size);
|
109
|
+
size = extattr_get(d, namespace1, StringValueCStr(name), StringValueCStr(buf), size);
|
110
|
+
if (size < 0) { rb_sys_fail(StringValueCStr(path)); }
|
111
|
+
rb_str_set_len(buf, size);
|
112
|
+
return buf;
|
113
|
+
}
|
114
|
+
|
115
|
+
static VALUE
|
116
|
+
file_extattr_get_main(VALUE file, int fd, int namespace1, VALUE name)
|
117
|
+
{
|
118
|
+
return extattr_get_common(extattr_get_fd, fd, RFILE(file)->fptr->pathv, namespace1, name);
|
119
|
+
}
|
120
|
+
|
121
|
+
static VALUE
|
122
|
+
file_s_extattr_get_main(VALUE path, int namespace1, VALUE name)
|
123
|
+
{
|
124
|
+
return extattr_get_common(extattr_get_file, (intptr_t)StringValueCStr(path), path, namespace1, name);
|
125
|
+
}
|
126
|
+
|
127
|
+
static VALUE
|
128
|
+
file_s_extattr_get_link_main(VALUE path, int namespace1, VALUE name)
|
129
|
+
{
|
130
|
+
return extattr_get_common(extattr_get_link, (intptr_t)StringValueCStr(path), path, namespace1, name);
|
131
|
+
}
|
132
|
+
|
133
|
+
|
134
|
+
static VALUE
|
135
|
+
extattr_set_common(ssize_t (*extattr_set)(), intptr_t d, int namespace1, VALUE name, VALUE data)
|
136
|
+
{
|
137
|
+
int status = extattr_set(d, namespace1, StringValueCStr(name), StringValueCStr(data), RSTRING_LEN(data));
|
138
|
+
if (status < 0) { rb_sys_fail("extattr_set call error"); }
|
139
|
+
return Qnil;
|
140
|
+
}
|
141
|
+
|
142
|
+
static VALUE
|
143
|
+
file_extattr_set_main(VALUE file, int fd, int namespace1, VALUE name, VALUE data)
|
144
|
+
{
|
145
|
+
return extattr_set_common(extattr_set_fd, fd, namespace1, name, data);
|
146
|
+
}
|
147
|
+
|
148
|
+
static VALUE
|
149
|
+
file_s_extattr_set_main(VALUE path, int namespace1, VALUE name, VALUE data)
|
150
|
+
{
|
151
|
+
return extattr_set_common(extattr_set_file, (intptr_t)StringValueCStr(path), namespace1, name, data);
|
152
|
+
}
|
153
|
+
|
154
|
+
static VALUE
|
155
|
+
file_s_extattr_set_link_main(VALUE path, int namespace1, VALUE name, VALUE data)
|
156
|
+
{
|
157
|
+
return extattr_set_common(extattr_set_link, (intptr_t)StringValueCStr(path), namespace1, name, data);
|
158
|
+
}
|
159
|
+
|
160
|
+
|
161
|
+
static VALUE
|
162
|
+
extattr_delete_common(int (*extattr_delete)(), intptr_t d, int namespace1, VALUE name)
|
163
|
+
{
|
164
|
+
int status = extattr_delete(d, namespace1, StringValueCStr(name), NULL, 0);
|
165
|
+
if (status < 0) { rb_sys_fail("extattr_delete call error"); }
|
166
|
+
return Qnil;
|
167
|
+
}
|
168
|
+
|
169
|
+
static VALUE
|
170
|
+
file_extattr_delete_main(VALUE file, int fd, int namespace1, VALUE name)
|
171
|
+
{
|
172
|
+
return extattr_delete_common(extattr_delete_fd, fd, namespace1, name);
|
173
|
+
}
|
174
|
+
|
175
|
+
static VALUE
|
176
|
+
file_s_extattr_delete_main(VALUE path, int namespace1, VALUE name)
|
177
|
+
{
|
178
|
+
return extattr_delete_common(extattr_delete_file, (intptr_t)StringValueCStr(path), namespace1, name);
|
179
|
+
}
|
180
|
+
|
181
|
+
static VALUE
|
182
|
+
file_s_extattr_delete_link_main(VALUE path, int namespace1, VALUE name)
|
183
|
+
{
|
184
|
+
return extattr_delete_common(extattr_delete_link, (intptr_t)StringValueCStr(path), namespace1, name);
|
185
|
+
}
|
186
|
+
|
187
|
+
|
188
|
+
static void
|
189
|
+
extattr_init_implement(void)
|
190
|
+
{
|
191
|
+
rb_define_const(mExtAttr, "IMPLEMENT", rb_str_freeze(rb_str_new_cstr("extattr")));
|
192
|
+
}
|