extattr 0.1.2 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 53957e04a2ee7834088849a2f73415f363d24e23
4
+ data.tar.gz: 2f649f3e25c9b0a8a0278a5f928298d2719d061e
5
+ SHA512:
6
+ metadata.gz: a2cff71bea005342d08ed40463d99a53259b88e2a2d421c9fae98719096f0fd6431e152159148750093813a30b1066ede5ea078e90798ef71d9ea1a4ad7e1fd9
7
+ data.tar.gz: cb69dfc4e4c68b2041694922917a35a56df7334d5a0c8c06c2def76bafe2a8e3c2e2c69d3105a3e9603b132ef2b8f46f24abc045c8e57142c6823488360c188f
@@ -1,3 +1,5 @@
1
+ #@markup markdown
2
+
1
3
  Copyright (c) 2012, dearblue. All rights reserved.
2
4
 
3
5
  Redistribution and use in source and binary forms, with or
@@ -0,0 +1,161 @@
1
+ # @markup markdown
2
+
3
+ # extattr
4
+
5
+ extattr is filesystem extended attributes operation library for FreeBSD, GNU/Linux and Microsoft Windows.
6
+
7
+ ***END OF DOCUMENT IN ENGLISH***
8
+
9
+ ----
10
+
11
+ ***START OF DOCUMENT IN JAPANESE***
12
+
13
+ extattr はファイルシステムの拡張属性を操作するライブラリで、FreeBSD、GNU/Linux、Windows に対応しています。
14
+
15
+ サポートされる環境で、統一的なメソッドを提供します。
16
+
17
+ 実装については、以下のようになっています。
18
+
19
+ - FreeBSD: extattr (`extattr_list`, `extattr_get`, `extattr_set`, `extattr_delete`)
20
+ - GNU/Linux: xattr (`listxattr`, `getxattr`, `setxattr`, `removexattr`)
21
+ - Microsoft Windows: NTFS ADS (代替データストリーム) / 拡張ファイル属性 (`NtQueryEaFile`, `NtSetEaFile`)
22
+
23
+
24
+ ## Support ruby version
25
+
26
+ - ruby-1.9.3+
27
+ - ruby-2.0+
28
+ - ruby-2.1+
29
+
30
+
31
+ ## Tested system
32
+
33
+ - PC-BSD/AMD64 10.0
34
+ - lubuntu 13.10 (i386)
35
+ - Microsoft Windows XP Professional SP3
36
+ - Microsoft Windows 7 Professional SP1
37
+
38
+
39
+ ## 簡易リファレンスマニュアル
40
+
41
+ クラスメソッドに『!』がついているものはシンボリックリンクに対する操作となります。
42
+
43
+ キーワード引数の `namespace` を与えると、拡張属性の名前空間を指定できます。
44
+
45
+ 規定値は `File::EXTATTR_NAMESPACE_USER` で、ほかの値は `File::EXTATTR_NAMESPACE_SYSTEM` のみが指定できます。
46
+
47
+
48
+ ### 拡張属性の属性名を取得
49
+
50
+ File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) -> array
51
+ File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
52
+ File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) -> array
53
+ File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
54
+ File#extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) -> array
55
+ File#extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
56
+
57
+ ### 拡張属性の要素の大きさを取得
58
+
59
+ File.extattr_size(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
60
+ File.extattr_size!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
61
+ File#extattr_size(name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
62
+
63
+ ### 拡張属性の要素を取得
64
+
65
+ File.extattr_get(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
66
+ File.extattr_get!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
67
+ File#extattr_get(name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
68
+
69
+ ### 拡張属性の要素を設定
70
+
71
+ File.extattr_set(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
72
+ File.extattr_set!(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
73
+ File#extattr_set(name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
74
+
75
+ ### 拡張属性の要素を削除
76
+
77
+ File.extattr_delete(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
78
+ File.extattr_delete!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
79
+ File#extattr_delete(name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
80
+
81
+ ### 拡張属性の属性名と要素を列挙する
82
+
83
+ File.extattr_each(path, namespace: File::EXTATTR_NAMESPACE_USER) -> Enumerator
84
+ File.extattr_each(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name, data| ... } -> nil
85
+ File.extattr_each!(path, namespace: File::EXTATTR_NAMESPACE_USER) -> Enumerator
86
+ File.extattr_each!(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name, data| ... } -> nil
87
+ File#extattr_each(namespace: File::EXTATTR_NAMESPACE_USER) -> Enumerator
88
+ File#extattr_each(namespace: File::EXTATTR_NAMESPACE_USER) { |name, data| ... } -> file
89
+
90
+
91
+ ## GNU/Linux における特記事項
92
+
93
+ - GNU/Linux で利用されている名前空間〈security〉〈trusted〉には未対応です。
94
+
95
+
96
+ ## Microsoft Windows における特記事項
97
+
98
+ - Windows XP 以降を必要とします。Win2k でも動作するかもしれません (未検証)。
99
+ Windows 9x シリーズでは `require "extattr"` の段階で例外が発生すると思われます (未検証)。
100
+ - `File::EXTATTR_NAMESPACE_USER` は (比較的よく利用される) NTFS ADS に対する操作で、`File::EXTATTR_NAMESPACE_SYSTEM` が本来の (あまり利用されていない) 拡張ファイル属性に対する操作となります。
101
+ - リパースポイント (ジャンクションやシンボリックリンク) に対する NTFS ADS は要素の取得や設定、削除は出来ません。
102
+ 必ずリンク先に対する操作となります (やり方がわかりません)。
103
+ - 64 KiB を超える NTFS ADS は取得も設定も出来ません。
104
+ これは『拡張属性』と捉えた場合、巨大なデータを扱えるべきではないという考えによるためです
105
+ (本当のところは FreeBSD の拡張属性が最大 64KiB 弱であることが由来です)。
106
+ - 巨大な NTFS ADS を扱いたい場合は、`File.open` でファイルとして扱えるので自由に読み書きできます。
107
+ これは ruby に限ったことではなく、Windows による仕様です。
108
+ この場合の与えるファイル名は、`path + ":" + name` という形になります。
109
+
110
+ filepath = "sample.txt"
111
+ extattrname = "category"
112
+ ntfs_ads_name = filepath + ":" + extattrname
113
+ File.open(ntfs_ads_name, "r") do |file|
114
+ ...
115
+ end
116
+
117
+ ## 既知のバグ
118
+
119
+ ### `extattr_list` のブロック内で `extattr_set` `extattr_delete` を行うと思いがけない副作用が起こる場合がある
120
+
121
+ 解決方法: `extattr_set` か `extattr_delete` のどちらかを同時に利用したい場合、`extattr_list.each` を用いてください。
122
+
123
+
124
+ ## 変更履歴
125
+
126
+ ### 0.1
127
+
128
+ はじめてのりりーす
129
+
130
+ - 拡張ファイル属性の一覧、取得、設定、削除を行うことが出来ます
131
+ - **セキュリティリスクあり**: `$SAFE` の確認や汚染状態の伝播を行ないません
132
+ - Windows 版では、NTFS ADS に対する操作となります。`File::EXTATTR_NAMESPACE_USER` のみが有効です
133
+
134
+ ### 0.2
135
+
136
+ - セーフレベルに関する改善
137
+ - `$SAFE` と汚染状態を確認するようになりました
138
+ - 汚染状態を伝播させるようになりました
139
+ - バージョン情報と実装 API に関する情報の取得
140
+ - `File::EXTATTR_VERSION` 定数によって、バージョン情報が取得できるようになりました
141
+ - `File::EXTATTR_IMPLEMENT` 定数によって、実装に関する情報が取得できるようになりました
142
+ - 機能の改善
143
+ - `File.extattr_each` / `File#extattr_each` によって、ファイル拡張属性の名前と値を繰り返し取得できるようになりました
144
+ - Windows 版に関する改善
145
+ - `File::EXTATTR_NAMESPACE_SYSTEM` によって、本来の拡張ファイル属性の操作が行えるようになりました
146
+ (NtQueryEaFile / NtSetEaFile)
147
+
148
+
149
+ ## 参考資料
150
+
151
+ - extattr
152
+ - <http://www.freebsd.org/cgi/man.cgi?query=extattr&sektion=2>
153
+ - xattr
154
+ - <http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/listxattr.2.html>
155
+ - windows
156
+ - <http://msdn.microsoft.com/en-us/library/cc232069.aspx>
157
+ - <http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/FILE_INFORMATION_CLASS.html>
158
+ - <http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtQueryInformationFile.html>
159
+ - <http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtQueryEaFile.html>
160
+ - <http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtSetEaFile.html>
161
+ - <http://www.zezula.net/en/fstools/filetest.html>
@@ -0,0 +1,105 @@
1
+ #vim: set fileencoding:utf-8
2
+
3
+ AUTHOR = "dearblue"
4
+ EMAIL = "dearblue@users.sourceforge.jp"
5
+ WEBSITE = "http://sourceforge.jp/projects/rutsubo/"
6
+ LICENSE = "2-clause BSD License"
7
+ PACKAGE = "extattr"
8
+ VERSION = "0.2"
9
+ PLATFORM_NATIVE = Gem::Platform.local.to_s
10
+ GEMFILE = "#{PACKAGE}-#{VERSION}.gem"
11
+ GEMFILE_NATIVE = "#{PACKAGE}-#{VERSION}-#{PLATFORM_NATIVE}.gem"
12
+ GEMSPEC = "#{PACKAGE}.gemspec"
13
+ GEMSPEC_NATIVE = "#{PACKAGE}-#{PLATFORM_NATIVE}.gemspec"
14
+ SUMMARY = "extended attribute operation library for ruby"
15
+ DESCRIPTION = <<EOS
16
+ extattr is extended file attribute operation library for ruby.
17
+ Supported for FreeBSD (extattr), GNU/Linux (xattr) and Microsoft Windows (NTFS ADS + Extended Attributes).
18
+ EOS
19
+
20
+ RUBY19 = ENV["RUBY19"]
21
+ RUBY20 = ENV["RUBY20"]
22
+ RUBY21 = ENV["RUBY21"]
23
+ RUBYSET = [RUBY19, RUBY20, RUBY21].compact
24
+
25
+ #RUBY_VERSIONS = [RUBY20].map { |ruby| [`#{ruby} -e "puts RUBY_VERSION"`.slice(/\d+\.\d+/), ruby] }
26
+ RUBY_VERSIONS = RUBYSET.map { |ruby| [`#{ruby} -e "puts RbConfig::CONFIG['ruby_version']"`.chomp, ruby] }
27
+
28
+ BINFILES = FileList["bin/*"]
29
+ EXTFILES = FileList["ext/{*.h,*.c,*.cc}"]
30
+ LIBFILES = FileList["lib/**/*.rb"]
31
+ SOFILES_SET = RUBY_VERSIONS.map { |(ver, ruby)| ["lib/#{ver}/#{PACKAGE}.so", ruby] }
32
+ SOFILES = SOFILES_SET.map { |(lib, ruby)| lib }
33
+ EXTCONF = FileList["ext/extconf.rb"]
34
+
35
+ SPECSTUB = Gem::Specification.new do |s|
36
+ s.name = PACKAGE
37
+ s.version = VERSION
38
+ s.summary = SUMMARY
39
+ s.description = DESCRIPTION
40
+ s.homepage = WEBSITE
41
+ s.license = LICENSE
42
+ s.author = AUTHOR
43
+ s.email = EMAIL
44
+ s.executables = BINFILES.map { |n| File.basename n }
45
+ s.files = %w(LICENSE.md README.md Rakefile) + FileList["spec/*.rb"] + BINFILES + EXTCONF + EXTFILES + LIBFILES
46
+ s.rdoc_options = %w(--charset UTF-8 --main README.md)
47
+ #s.rdoc_options = %w(--charset UTF-8 --locale ja --main README.md)
48
+ s.has_rdoc = false
49
+ s.required_ruby_version = ">= 1.9.3"
50
+ s.add_development_dependency "rspec", "~> 2.14"
51
+ s.add_development_dependency "rake", "~> 10.0"
52
+ end
53
+
54
+
55
+ task :default => :gem
56
+ task :gem => [GEMFILE_NATIVE, GEMFILE]
57
+ task :gemspec => GEMSPEC
58
+ task :gemspec_native => GEMSPEC_NATIVE
59
+ task :gemfile => GEMFILE
60
+ task :gemfile_native => GEMFILE_NATIVE
61
+
62
+ task :rdoc do
63
+ sh "yardoc --charset UTF-8 --locale ja --main README.md README.md LICENSE.md #{(EXTFILES + LIBFILES).join(" ")}"
64
+ end
65
+
66
+
67
+ file GEMFILE => [GEMSPEC] + BINFILES + EXTFILES + LIBFILES do
68
+ sh "gem build #{GEMSPEC}"
69
+ end
70
+
71
+ file GEMFILE_NATIVE => [GEMSPEC_NATIVE] + BINFILES + EXTFILES + LIBFILES + SOFILES do
72
+ sh "gem build #{GEMSPEC_NATIVE}"
73
+ end
74
+
75
+ file GEMSPEC => __FILE__ do
76
+ s = SPECSTUB.dup
77
+ s.extensions += EXTCONF
78
+ File.write(GEMSPEC, s.to_ruby, mode: "wb")
79
+ end
80
+
81
+ file GEMSPEC_NATIVE => __FILE__ do
82
+ s = SPECSTUB.dup
83
+ s.files += SOFILES
84
+ s.platform = PLATFORM_NATIVE
85
+ File.write(GEMSPEC_NATIVE, s.to_ruby, mode: "wb")
86
+ end
87
+
88
+ SOFILES_SET.each do |(soname, ruby)|
89
+ sodir = File.dirname(soname)
90
+ makefile = File.join(sodir, "Makefile")
91
+
92
+ directory sodir
93
+
94
+ file soname => [makefile] + EXTFILES do
95
+ cd sodir do
96
+ sh "make"
97
+ end
98
+ end
99
+
100
+ file makefile => [sodir] + EXTCONF do
101
+ cd sodir do
102
+ sh "#{ruby} ../../ext/extconf.rb"
103
+ end
104
+ end
105
+ 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(int (*extattr_list)(), intptr_t d, int namespace1)
26
+ {
27
+ int size = extattr_list(d, namespace1, NULL, 0);
28
+ if (size < 0) { rb_sys_fail("extattr_list call error"); }
29
+ return size;
30
+ }
31
+
32
+ static VALUE
33
+ extattr_list_common(int (*extattr_list)(), intptr_t d, VALUE infection_source, int namespace1)
34
+ {
35
+ size_t size = get_extattr_list_size(extattr_list, d, 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) { rb_sys_fail("extattr_list call error"); }
41
+
42
+ VALUE list = Qnil;
43
+ if (rb_block_given_p()) {
44
+ extattr_list_name(ptr, size1, infection_source,
45
+ (void (*)(void *, VALUE))rb_yield_values, (void *)(1));
46
+ } else {
47
+ list = rb_ary_new();
48
+ OBJ_INFECT(list, infection_source);
49
+ extattr_list_name(ptr, size1, infection_source,
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(int (*extattr_get)(), intptr_t d, int namespace1, VALUE name)
78
+ {
79
+ ssize_t size = extattr_get(d, namespace1, RSTRING_PTR(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(int (*extattr_get)(), intptr_t d, VALUE path, int namespace1, VALUE name)
105
+ {
106
+ ssize_t size = extattr_get(d, namespace1, RSTRING_PTR(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, RSTRING_PTR(name), RSTRING_PTR(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(int (*extattr_set)(), intptr_t d, int namespace1, VALUE name, VALUE data)
136
+ {
137
+ int status = extattr_set(d, namespace1, RSTRING_PTR(name), RSTRING_PTR(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, RSTRING_PTR(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
+ ext_init_implement(void)
190
+ {
191
+ rb_define_const(rb_cFile, "EXTATTR_IMPLEMANT", rb_str_freeze(rb_str_new_cstr("extattr")));
192
+ }