extattr 0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +46 -26
- data/ext/extattr.c +2 -2
- data/ext/extattr.linux +50 -37
- data/ext/extattr.windows +93 -60
- data/ext/extconf.rb +4 -1
- data/rspecs/extattr.rb +16 -7
- metadata +2 -2
data/README.txt
CHANGED
@@ -1,53 +1,73 @@
|
|
1
1
|
= extattr
|
2
2
|
|
3
|
-
extattr is extended
|
3
|
+
extattr is filesystem extended attributes operation library for FreeBSD, GNU/Linux and Microsoft Windows.
|
4
4
|
|
5
5
|
----
|
6
6
|
|
7
|
-
extattr
|
7
|
+
extattr はファイルシステムの拡張属性を操作するライブラリで、FreeBSD、GNU/Linux、Windows に対応しています。
|
8
8
|
|
9
9
|
サポートされる環境で、統一的なメソッドを提供します。
|
10
10
|
|
11
|
-
クラスメソッドに『!』がついているものはシンボリックリンクに対する操作となります。
|
12
11
|
|
13
|
-
|
12
|
+
== test system
|
13
|
+
|
14
|
+
- Microsoft Windows XP Professional SP3
|
15
|
+
- PC-BSD/AMD64 9.0
|
16
|
+
- lubuntu 12.04
|
17
|
+
|
18
|
+
|
19
|
+
== 簡易リファレンスマニュアル
|
20
|
+
|
21
|
+
クラスメソッドに『!』がついているものはシンボリックリンクに対する操作となります。
|
14
22
|
|
23
|
+
キーワード引数の <code>namespace</code> を与えると、拡張属性の名前空間を指定できます。
|
24
|
+
規定値は <code>EXTATTR_NAMESPACE_USER</code> で、ほかの値は <code>EXTATTR_NAMESPACE_SYSTEM</code> のみが指定できます
|
25
|
+
(Windows 版では <code>EXTATTR_NAMESPACE_USER</code> のみが指定可能です)。
|
15
26
|
|
16
|
-
|
27
|
+
拡張属性の属性名を取得:
|
17
28
|
|
18
|
-
|
19
|
-
|
20
|
-
|
29
|
+
File#extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) -> array
|
30
|
+
File#extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
|
31
|
+
File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) -> array
|
32
|
+
File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
|
33
|
+
File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) -> array
|
34
|
+
File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
|
21
35
|
|
22
|
-
|
36
|
+
拡張属性の要素の大きさを取得:
|
23
37
|
|
24
|
-
|
25
|
-
|
26
|
-
|
38
|
+
File#extattr_size(name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
|
39
|
+
File.extattr_size(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
|
40
|
+
File.extattr_size!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
|
27
41
|
|
28
|
-
|
42
|
+
拡張属性の要素を取得:
|
29
43
|
|
30
|
-
|
31
|
-
|
32
|
-
|
44
|
+
File#extattr_get(name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
|
45
|
+
File.extattr_get(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
|
46
|
+
File.extattr_get!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
|
33
47
|
|
34
|
-
|
48
|
+
拡張属性の要素を設定:
|
35
49
|
|
36
|
-
|
37
|
-
|
38
|
-
|
50
|
+
File#extattr_set(name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
|
51
|
+
File.extattr_set(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
|
52
|
+
File.extattr_set!(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
|
39
53
|
|
40
|
-
|
54
|
+
拡張属性の要素を削除:
|
41
55
|
|
42
|
-
|
43
|
-
|
44
|
-
|
56
|
+
File#extattr_delete(name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
|
57
|
+
File.extattr_delete(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
|
58
|
+
File.extattr_delete!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
|
45
59
|
|
46
60
|
|
47
61
|
== Microsoft Windows における諸注意
|
48
62
|
|
49
63
|
Windows 2000 以降でのみ動作します。Windows 9X シリーズでは <code>require "extattr"</code> の段階で例外が発生するでしょう。
|
50
64
|
|
51
|
-
リパースポイント (ジャンクションやシンボリックリンク) に対する ADS
|
65
|
+
リパースポイント (ジャンクションやシンボリックリンク) に対する ADS は要素の取得や設定、削除は出来ません。
|
66
|
+
必ずリンク先に対する操作となります。
|
52
67
|
|
53
|
-
|
68
|
+
64 KiB を超える ADS は取得も設定も出来ません。
|
69
|
+
これは『拡張属性』と捉えた場合、巨大なデータを扱えるべきではないという考えによるためです
|
70
|
+
(本当のところは FreeBSD の拡張属性が最大 64KiB 弱であることが由来です)。
|
71
|
+
巨大な ADS を扱いたい場合は、<code>File.open</code> でファイルとして扱えるので自由に読み書きできます
|
72
|
+
(これは ruby に限ったことではなく、Windows による仕様です)。
|
73
|
+
この場合の与えるファイル名は、<code>path + ":" + name</code> という形になります。
|
data/ext/extattr.c
CHANGED
@@ -61,10 +61,10 @@ file2fd(VALUE file)
|
|
61
61
|
|
62
62
|
#if defined(HAVE_SYS_EXTATTR_H)
|
63
63
|
# include "extattr.bsd"
|
64
|
-
#elif defined(HAVE_ATTR_XATTR_H)
|
65
|
-
# include "extattr.linux"
|
66
64
|
#elif defined(HAVE_WINNT_H)
|
67
65
|
# include "extattr.windows"
|
66
|
+
#elif defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
|
67
|
+
# include "extattr.linux"
|
68
68
|
#else
|
69
69
|
# error ruby extattr not supported on your system
|
70
70
|
#endif
|
data/ext/extattr.linux
CHANGED
@@ -1,33 +1,39 @@
|
|
1
1
|
#include <sys/types.h>
|
2
|
-
#
|
2
|
+
#if HAVE_ATTR_XATTR_H
|
3
|
+
# include <attr/xattr.h>
|
4
|
+
#else
|
5
|
+
# include <sys/xattr.h>
|
6
|
+
#endif
|
7
|
+
|
8
|
+
enum {
|
9
|
+
EXTATTR_NAMESPACE_USER,
|
10
|
+
EXTATTR_NAMESPACE_SYSTEM,
|
11
|
+
EXTATTR_NAMESPACE_TRUSTED,
|
12
|
+
EXTATTR_NAMESPACE_SECURITY,
|
13
|
+
};
|
3
14
|
|
4
|
-
#define EXTATTR_NAMESPACE_USER 0
|
5
|
-
#define EXTATTR_NAMESPACE_SYSTEM 1
|
6
15
|
|
7
16
|
static VALUE NAMESPACE_USER_PREFIX, NAMESPACE_SYSTEM_PREFIX;
|
8
17
|
|
9
18
|
|
10
19
|
static VALUE
|
11
|
-
|
20
|
+
xattr_name(int namespace, VALUE name)
|
12
21
|
{
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
VALUE list;
|
22
|
-
if (rb_block_given_p()) {
|
23
|
-
reduce = (VALUE (*)(void *, VALUE))rb_yield_values;
|
24
|
-
first = (void *)1;
|
25
|
-
list = Qnil;
|
26
|
-
} else {
|
27
|
-
reduce = (VALUE (*)(void *, VALUE))rb_ary_push;
|
28
|
-
first = (void *)(list = rb_ary_new());
|
22
|
+
switch (namespace) {
|
23
|
+
case EXTATTR_NAMESPACE_USER:
|
24
|
+
return rb_str_plus(NAMESPACE_USER_PREFIX, name);
|
25
|
+
case EXTATTR_NAMESPACE_SYSTEM:
|
26
|
+
return rb_str_plus(NAMESPACE_SYSTEM_PREFIX, name);
|
27
|
+
default:
|
28
|
+
rb_raise(rb_eRuntimeError, "namespace error");
|
29
|
+
return Qnil;
|
29
30
|
}
|
31
|
+
}
|
32
|
+
|
30
33
|
|
34
|
+
static inline void
|
35
|
+
extattr_list_name(const char *ptr, size_t size, int namespace, VALUE (*reduce)(void *, VALUE), void *user)
|
36
|
+
{
|
31
37
|
const char *end = ptr + size;
|
32
38
|
while (ptr < end) {
|
33
39
|
int len = strlen(ptr);
|
@@ -42,11 +48,32 @@ extattr_list0(ssize_t (*func)(), void *d, int namespace)
|
|
42
48
|
}
|
43
49
|
|
44
50
|
name = rb_str_new_cstr(ptr);
|
45
|
-
reduce(
|
51
|
+
reduce(user, name);
|
46
52
|
ptr += RSTRING_LEN(name) + 1; // 最後の『+1』は、ヌルバイトの分。
|
47
53
|
}
|
54
|
+
}
|
55
|
+
|
56
|
+
static VALUE
|
57
|
+
extattr_list0(ssize_t (*func)(), void *d, int namespace)
|
58
|
+
{
|
59
|
+
ssize_t size = 65536;
|
60
|
+
VALUE buf = rb_str_buf_new(size);
|
61
|
+
char *ptr = RSTRING_PTR(buf);
|
62
|
+
size = func(d, ptr, size);
|
63
|
+
if (size < 0) { rb_sys_fail("listxattr call error"); }
|
48
64
|
|
49
|
-
|
65
|
+
if (rb_block_given_p()) {
|
66
|
+
extattr_list_name(ptr, size, namespace,
|
67
|
+
(VALUE (*)(void *, VALUE))rb_yield_values,
|
68
|
+
(void *)1);
|
69
|
+
return Qnil;
|
70
|
+
} else {
|
71
|
+
VALUE list = rb_ary_new();
|
72
|
+
extattr_list_name(ptr, size, namespace,
|
73
|
+
(VALUE (*)(void *, VALUE))rb_ary_push,
|
74
|
+
(void *)list);
|
75
|
+
return list;
|
76
|
+
}
|
50
77
|
}
|
51
78
|
|
52
79
|
static VALUE
|
@@ -68,20 +95,6 @@ file_s_extattr_list_link0(VALUE path, int namespace)
|
|
68
95
|
}
|
69
96
|
|
70
97
|
|
71
|
-
static VALUE
|
72
|
-
xattr_name(int namespace, VALUE name)
|
73
|
-
{
|
74
|
-
switch (namespace) {
|
75
|
-
case EXTATTR_NAMESPACE_USER:
|
76
|
-
return rb_str_plus(NAMESPACE_USER_PREFIX, name);
|
77
|
-
case EXTATTR_NAMESPACE_SYSTEM:
|
78
|
-
return rb_str_plus(NAMESPACE_SYSTEM_PREFIX, name);
|
79
|
-
default:
|
80
|
-
rb_raise(rb_eRuntimeError, "namespace error");
|
81
|
-
return Qnil;
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
98
|
static VALUE
|
86
99
|
extattr_size0(ssize_t (*func)(), void *d, int namespace, VALUE name)
|
87
100
|
{
|
@@ -146,7 +159,7 @@ static VALUE
|
|
146
159
|
extattr_set0(int (*func)(), void *d, int namespace, VALUE name, VALUE data)
|
147
160
|
{
|
148
161
|
name = xattr_name(namespace, name);
|
149
|
-
int status = func(d, StringValueCStr(name), RSTRING_PTR(data), RSTRING_LEN(data));
|
162
|
+
int status = func(d, StringValueCStr(name), RSTRING_PTR(data), RSTRING_LEN(data), 0);
|
150
163
|
if (status < 0) { rb_sys_fail("getxattr call error"); }
|
151
164
|
return Qnil;
|
152
165
|
}
|
data/ext/extattr.windows
CHANGED
@@ -6,24 +6,27 @@
|
|
6
6
|
#include <ntdef.h>
|
7
7
|
#include <psapi.h>
|
8
8
|
#include <wchar.h>
|
9
|
+
#include <ruby/win32.h>
|
9
10
|
|
10
11
|
#define EXTATTR_NAMESPACE_USER 0
|
11
12
|
#define EXTATTR_NAMESPACE_SYSTEM 1
|
12
13
|
|
13
14
|
/*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
* TODO:
|
15
|
+
* - TODO: バッファサイズの確保量が結構大きめ。最適化をするべき。
|
16
|
+
* - TODO: CloseHandle してないところがありすぎ。修正。
|
17
|
+
* - TODO: Win9X シリーズだとこのライブラリ読み込みすら出来ない。
|
18
|
+
* メソッド定義だけは行うようにするべき? (実際に呼び出したら NotImplementedError 例外を投げる、とか)
|
19
|
+
* - リパースポイントって、ADSはつけられないのかな? 操作方法がわからない。
|
17
20
|
*/
|
18
|
-
static const size_t EXTATTR_MAX = 131072;
|
19
21
|
|
20
22
|
/*
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
24
|
-
*
|
25
|
-
*
|
23
|
+
* ADS は普通のファイルのように扱えるから、extattr とみなして扱う場合は容量の制限を設けることにする。
|
24
|
+
*
|
25
|
+
* ruby-extattr で不十分な巨大なデータを扱う場合は File.open で開くことが出来るので必要であればそちらで。
|
26
|
+
*
|
27
|
+
* TODO: 最適値を探すべき
|
26
28
|
*/
|
29
|
+
static const size_t EXTATTR_MAX = 65536;
|
27
30
|
|
28
31
|
|
29
32
|
static rb_encoding *ENCutf8p;
|
@@ -32,8 +35,6 @@ static rb_encoding *ENCutf16lep;
|
|
32
35
|
static VALUE ENCutf16le;
|
33
36
|
|
34
37
|
|
35
|
-
|
36
|
-
|
37
38
|
static VALUE
|
38
39
|
str2wcs(VALUE str)
|
39
40
|
{
|
@@ -90,7 +91,7 @@ wpath2str(const wchar_t path[], size_t size)
|
|
90
91
|
static VALUE
|
91
92
|
adsname2str(const wchar_t name[], size_t size)
|
92
93
|
{
|
93
|
-
if (name[0] == L':' && wcsncmp(name + size - 6, L":$DATA", 6) == 0) {
|
94
|
+
if (name[0] == L':' && size >= 7 && wcsncmp(name + size - 6, L":$DATA", 6) == 0) {
|
94
95
|
name += 1;
|
95
96
|
size -= 7;
|
96
97
|
}
|
@@ -100,9 +101,15 @@ adsname2str(const wchar_t name[], size_t size)
|
|
100
101
|
|
101
102
|
|
102
103
|
static void
|
103
|
-
raise_win32_error(DWORD status)
|
104
|
+
raise_win32_error(DWORD status, VALUE name)
|
104
105
|
{
|
105
|
-
|
106
|
+
if (NIL_P(name)) {
|
107
|
+
VALUE args[] = { INT2NUM(rb_w32_map_errno(status)), };
|
108
|
+
rb_exc_raise(rb_class_new_instance(1, args, rb_eSystemCallError));
|
109
|
+
} else {
|
110
|
+
VALUE args[] = { StringValue(name), INT2NUM(rb_w32_map_errno(status)), };
|
111
|
+
rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemCallError));
|
112
|
+
}
|
106
113
|
}
|
107
114
|
|
108
115
|
static void
|
@@ -111,6 +118,15 @@ raise_ntstatus_error(NTSTATUS status)
|
|
111
118
|
rb_raise(rb_eSystemCallError, "NTSTATUS error - %u (%08Xh)", status, status);
|
112
119
|
}
|
113
120
|
|
121
|
+
static void
|
122
|
+
check_status_error(NTSTATUS status)
|
123
|
+
{
|
124
|
+
if (status != STATUS_SUCCESS) {
|
125
|
+
raise_ntstatus_error(status);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
|
114
130
|
static VALUE
|
115
131
|
get_filepath(HANDLE file)
|
116
132
|
{
|
@@ -121,7 +137,8 @@ get_filepath(HANDLE file)
|
|
121
137
|
RSTRING_PTR(buf),
|
122
138
|
size,
|
123
139
|
&size);
|
124
|
-
|
140
|
+
check_status_error(status);
|
141
|
+
|
125
142
|
const OBJECT_NAME_INFORMATION *info = (const OBJECT_NAME_INFORMATION *)RSTRING_PTR(buf);
|
126
143
|
if (wcsnicmp(info->Name.Buffer, L"\\Device\\", 8) == 0) {
|
127
144
|
// 先頭の "/Device/" を "//?/" に置き換える
|
@@ -138,7 +155,7 @@ get_filesize(HANDLE file)
|
|
138
155
|
BY_HANDLE_FILE_INFORMATION info;
|
139
156
|
|
140
157
|
if (!GetFileInformationByHandle(file, &info)) {
|
141
|
-
raise_win32_error(GetLastError());
|
158
|
+
raise_win32_error(GetLastError(), Qnil);
|
142
159
|
}
|
143
160
|
|
144
161
|
return ((uint64_t)info.nFileSizeHigh << 32) | info.nFileSizeLow;
|
@@ -163,35 +180,47 @@ check_namespace(int namespace)
|
|
163
180
|
}
|
164
181
|
|
165
182
|
|
166
|
-
static
|
167
|
-
|
183
|
+
static void
|
184
|
+
extattr_list_name(const char *ptr, void *(*yield)(void *user, VALUE name), void *user)
|
168
185
|
{
|
169
|
-
VALUE iostatusblock = rb_str_buf_new(4096);
|
170
|
-
VALUE infobuf = rb_str_buf_new(65536);
|
171
|
-
rb_str_set_len(infobuf, 65536);
|
172
|
-
NTSTATUS status = NtQueryInformationFile(file,
|
173
|
-
(PIO_STATUS_BLOCK)RSTRING_PTR(iostatusblock),
|
174
|
-
RSTRING_PTR(infobuf), RSTRING_LEN(infobuf),
|
175
|
-
FileStreamInformation);
|
176
|
-
if (status != 0) { raise_ntstatus_error(status); }
|
177
|
-
const char *ptr = RSTRING_PTR(infobuf);
|
178
|
-
VALUE list = Qnil;
|
179
|
-
if (!rb_block_given_p()) { list = rb_ary_new(); }
|
180
186
|
for (;;) {
|
181
187
|
const FILE_STREAM_INFORMATION *info = (const FILE_STREAM_INFORMATION *)ptr;
|
182
188
|
VALUE name = adsname2str(info->StreamName, info->StreamNameLength / 2);
|
183
189
|
if (RSTRING_LEN(name) > 0) {
|
184
|
-
|
185
|
-
rb_yield(name);
|
186
|
-
} else {
|
187
|
-
rb_ary_push(list, name);
|
188
|
-
}
|
190
|
+
yield(user, name);
|
189
191
|
}
|
190
192
|
size_t size = info->NextEntryOffset;
|
191
193
|
if (size == 0) { break; }
|
192
194
|
ptr += size;
|
193
195
|
}
|
194
|
-
|
196
|
+
}
|
197
|
+
|
198
|
+
static VALUE
|
199
|
+
extattr_list0(HANDLE file)
|
200
|
+
{
|
201
|
+
VALUE iostatusblock = rb_str_buf_new(4096);
|
202
|
+
size_t size = 65536; // TODO: 最適値を見つける
|
203
|
+
VALUE infobuf = rb_str_buf_new(size);
|
204
|
+
char *ptr = RSTRING_PTR(infobuf);
|
205
|
+
memset(ptr, 0, sizeof(FILE_STREAM_INFORMATION));
|
206
|
+
NTSTATUS status = NtQueryInformationFile(file,
|
207
|
+
(PIO_STATUS_BLOCK)RSTRING_PTR(iostatusblock),
|
208
|
+
ptr, size,
|
209
|
+
FileStreamInformation);
|
210
|
+
check_status_error(status);
|
211
|
+
|
212
|
+
if (rb_block_given_p()) {
|
213
|
+
extattr_list_name(ptr,
|
214
|
+
(void *(*)(void *, VALUE))rb_yield_values,
|
215
|
+
(void *)1);
|
216
|
+
return Qnil;
|
217
|
+
} else {
|
218
|
+
VALUE list = rb_ary_new();
|
219
|
+
extattr_list_name(ptr,
|
220
|
+
(void *(*)(void *, VALUE))rb_ary_push,
|
221
|
+
(void *)list);
|
222
|
+
return list;
|
223
|
+
}
|
195
224
|
}
|
196
225
|
|
197
226
|
static VALUE
|
@@ -242,12 +271,13 @@ static VALUE
|
|
242
271
|
file_s_extattr_list0(VALUE path, int namespace)
|
243
272
|
{
|
244
273
|
check_namespace(namespace);
|
245
|
-
|
274
|
+
VALUE path1 = path;
|
275
|
+
HANDLE file = CreateFileW(STR2WPATH(path1), 0,
|
246
276
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
247
277
|
NULL, 3,
|
248
278
|
FILE_FLAG_BACKUP_SEMANTICS,
|
249
279
|
0);
|
250
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
|
280
|
+
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
251
281
|
return rb_ensure(extattr_list0, (VALUE)file, file_close, (VALUE)file);
|
252
282
|
}
|
253
283
|
|
@@ -255,12 +285,13 @@ static VALUE
|
|
255
285
|
file_s_extattr_list_link0(VALUE path, int namespace)
|
256
286
|
{
|
257
287
|
check_namespace(namespace);
|
258
|
-
|
288
|
+
VALUE path1 = path;
|
289
|
+
HANDLE file = CreateFileW(STR2WPATH(path1), 0,
|
259
290
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
260
291
|
NULL, 3,
|
261
292
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
262
293
|
0);
|
263
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
|
294
|
+
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
264
295
|
return rb_ensure(extattr_list0, (VALUE)file, file_close, (VALUE)file);
|
265
296
|
}
|
266
297
|
|
@@ -268,14 +299,14 @@ static VALUE
|
|
268
299
|
file_s_extattr_size0(VALUE path, int namespace, VALUE name)
|
269
300
|
{
|
270
301
|
check_namespace(namespace);
|
271
|
-
|
272
|
-
rb_str_append(
|
273
|
-
HANDLE file = CreateFileW(STR2WPATH(
|
302
|
+
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
303
|
+
rb_str_append(path1, name);
|
304
|
+
HANDLE file = CreateFileW(STR2WPATH(path1), 0,
|
274
305
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
275
306
|
NULL, 3,
|
276
307
|
FILE_FLAG_BACKUP_SEMANTICS,
|
277
308
|
0);
|
278
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
|
309
|
+
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
279
310
|
return rb_ensure(extattr_size0, (VALUE)file, file_close, (VALUE)file);
|
280
311
|
}
|
281
312
|
|
@@ -283,14 +314,14 @@ static VALUE
|
|
283
314
|
file_s_extattr_size_link0(VALUE path, int namespace, VALUE name)
|
284
315
|
{
|
285
316
|
check_namespace(namespace);
|
286
|
-
|
287
|
-
rb_str_append(
|
288
|
-
HANDLE file = CreateFileW(STR2WPATH(
|
317
|
+
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
318
|
+
rb_str_append(path1, name);
|
319
|
+
HANDLE file = CreateFileW(STR2WPATH(path1), 0,
|
289
320
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
290
321
|
NULL, 3,
|
291
322
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
292
323
|
0);
|
293
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
|
324
|
+
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
294
325
|
return rb_ensure(extattr_size0, (VALUE)file, file_close, (VALUE)file);
|
295
326
|
}
|
296
327
|
|
@@ -306,7 +337,7 @@ extattr_get0(VALUE args[3])
|
|
306
337
|
VALUE buf = rb_str_buf_new(size);
|
307
338
|
DWORD readsize = 0;
|
308
339
|
if (!ReadFile(file, RSTRING_PTR(buf), size, &readsize, NULL)) {
|
309
|
-
raise_win32_error(GetLastError());
|
340
|
+
raise_win32_error(GetLastError(), Qnil);
|
310
341
|
}
|
311
342
|
rb_str_set_len(buf, readsize);
|
312
343
|
return buf;
|
@@ -316,14 +347,14 @@ static VALUE
|
|
316
347
|
extattr_get1(VALUE path, int flags, int namespace, VALUE name)
|
317
348
|
{
|
318
349
|
check_namespace(namespace);
|
319
|
-
|
320
|
-
rb_str_append(
|
321
|
-
HANDLE file = CreateFileW(STR2WPATH(
|
350
|
+
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
351
|
+
rb_str_append(path1, name);
|
352
|
+
HANDLE file = CreateFileW(STR2WPATH(path1), GENERIC_READ,
|
322
353
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
323
354
|
NULL, 3,
|
324
355
|
FILE_FLAG_BACKUP_SEMANTICS | flags,
|
325
356
|
0);
|
326
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
|
357
|
+
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
327
358
|
VALUE args[] = { (VALUE)file, (VALUE)namespace, name, };
|
328
359
|
return rb_ensure(extattr_get0, (VALUE)args, file_close, (VALUE)file);
|
329
360
|
}
|
@@ -351,7 +382,7 @@ extattr_set0(VALUE args[])
|
|
351
382
|
if (size > EXTATTR_MAX) { rb_raise(rb_eSystemCallError, "extattr too huge"); }
|
352
383
|
DWORD wrotesize = size;
|
353
384
|
if (!WriteFile(file, RSTRING_PTR(data), size, &wrotesize, NULL)) {
|
354
|
-
raise_win32_error(GetLastError());
|
385
|
+
raise_win32_error(GetLastError(), Qnil);
|
355
386
|
}
|
356
387
|
return Qnil;
|
357
388
|
}
|
@@ -360,14 +391,14 @@ static VALUE
|
|
360
391
|
file_s_extattr_set0(VALUE path, int namespace, VALUE name, VALUE data)
|
361
392
|
{
|
362
393
|
check_namespace(namespace);
|
363
|
-
|
364
|
-
rb_str_append(
|
365
|
-
HANDLE file = CreateFileW(STR2WPATH(
|
394
|
+
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
395
|
+
rb_str_append(path1, name);
|
396
|
+
HANDLE file = CreateFileW(STR2WPATH(path1), GENERIC_WRITE,
|
366
397
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
367
398
|
NULL, CREATE_ALWAYS,
|
368
399
|
FILE_FLAG_BACKUP_SEMANTICS,
|
369
400
|
0);
|
370
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
|
401
|
+
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
371
402
|
VALUE args[] = { (VALUE)file, (VALUE)namespace, name, data };
|
372
403
|
return rb_ensure(extattr_set0, (VALUE)args, file_close, (VALUE)file);
|
373
404
|
}
|
@@ -382,9 +413,11 @@ static VALUE
|
|
382
413
|
file_s_extattr_delete0(VALUE path, int namespace, VALUE name)
|
383
414
|
{
|
384
415
|
check_namespace(namespace);
|
385
|
-
|
386
|
-
rb_str_append(
|
387
|
-
DeleteFileW(STR2WPATH(
|
416
|
+
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
417
|
+
rb_str_append(path1, name);
|
418
|
+
if (!DeleteFileW(STR2WPATH(path1))) {
|
419
|
+
raise_win32_error(GetLastError(), path);
|
420
|
+
}
|
388
421
|
return Qnil;
|
389
422
|
}
|
390
423
|
|
data/ext/extconf.rb
CHANGED
@@ -9,10 +9,13 @@ require "mkmf"
|
|
9
9
|
|
10
10
|
case
|
11
11
|
when have_header("sys/extattr.h")
|
12
|
-
when have_header("attr/xattr.h")
|
13
12
|
when have_header("winnt.h") && have_header("ntdef.h") && have_header("psapi.h") &&
|
14
13
|
have_header("ddk/ntifs.h") && have_header("ddk/winddk.h") &&
|
15
14
|
have_library("ntoskrnl") && have_library("ntdll") && have_library("psapi")
|
15
|
+
when have_header("attr/xattr.h")
|
16
|
+
$CPPFLAGS << " -DLINUX_XATTR_H=\\<attr/xattr.h\\>"
|
17
|
+
when have_header("sys/xattr.h")
|
18
|
+
$CPPFLAGS << " -DLINUX_XATTR_H=\\<sys/xattr.h\\>"
|
16
19
|
else
|
17
20
|
$stderr.puts <<-EOS
|
18
21
|
#$0: not supported target.
|
data/rspecs/extattr.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "tmpdir"
|
4
4
|
basedir = File.join(Dir.tmpdir, "ruby-extattr.test-work")
|
5
5
|
Dir.mkdir basedir unless File.directory? basedir
|
6
|
+
filepath = File.join(basedir, "file1")
|
6
7
|
|
7
8
|
require "extattr"
|
8
9
|
|
@@ -12,7 +13,7 @@ Dir.chdir basedir do
|
|
12
13
|
describe "file" do
|
13
14
|
file = nil
|
14
15
|
before(:all) do
|
15
|
-
file = File.open(
|
16
|
+
file = File.open(filepath, "a")
|
16
17
|
end
|
17
18
|
|
18
19
|
it ".extattr_list" do
|
@@ -26,28 +27,36 @@ Dir.chdir basedir do
|
|
26
27
|
end
|
27
28
|
|
28
29
|
describe File do
|
30
|
+
before(:all) do
|
31
|
+
File.open(filepath, "a") {}
|
32
|
+
end
|
33
|
+
|
29
34
|
it ".extattr_list" do
|
30
|
-
File.extattr_list(
|
35
|
+
File.extattr_list(filepath).should eq([])
|
31
36
|
end
|
32
37
|
|
33
38
|
it ".extattr_set" do
|
34
|
-
File.extattr_set(
|
39
|
+
File.extattr_set(filepath, "ext1", extdata).should nil
|
35
40
|
end
|
36
41
|
|
37
42
|
it ".extattr_list ((2))" do
|
38
|
-
File.extattr_list(
|
43
|
+
File.extattr_list(filepath).should eq(["ext1"])
|
39
44
|
end
|
40
45
|
|
41
46
|
it ".extattr_get" do
|
42
|
-
File.extattr_get(
|
47
|
+
File.extattr_get(filepath, "ext1").should eq(extdata)
|
43
48
|
end
|
44
49
|
|
45
50
|
it ".extattr_delete" do
|
46
|
-
File.extattr_delete(
|
51
|
+
File.extattr_delete(filepath, "ext1").should nil
|
47
52
|
end
|
48
53
|
|
49
54
|
it ".extattr_list ((3))" do
|
50
|
-
File.extattr_list(
|
55
|
+
File.extattr_list(filepath).should eq([])
|
56
|
+
end
|
57
|
+
|
58
|
+
after(:all) do
|
59
|
+
File.unlink filepath
|
51
60
|
end
|
52
61
|
end
|
53
62
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: extattr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-03 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'extattr is extended attribute operation library for ruby.
|
15
15
|
|