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 CHANGED
@@ -1,53 +1,73 @@
1
1
  = extattr
2
2
 
3
- extattr is extended attribute operation library for Windows and FreeBSD.
3
+ extattr is filesystem extended attributes operation library for FreeBSD, GNU/Linux and Microsoft Windows.
4
4
 
5
5
  ----
6
6
 
7
- extattr は拡張属性を操作するライブラリで、WindowsFreeBSD に対応しています (GNU/Linux はコードを書いてみただけで、試験がまったくされていません)。
7
+ extattr はファイルシステムの拡張属性を操作するライブラリで、FreeBSD、GNU/Linux、Windows に対応しています。
8
8
 
9
9
  サポートされる環境で、統一的なメソッドを提供します。
10
10
 
11
- クラスメソッドに『!』がついているものはシンボリックリンクに対する操作となります。
12
11
 
13
- キーワード引数の <code>namespace</code> を与えると、拡張属性の名前空間を指定できます。規定値は <code>EXTATTR_NAMESPACE_USER</code> で、ほかの値は <code>EXTATTR_NAMESPACE_SYSTEM</code> のみが指定できます (Windows 版では <code>EXTATTR_NAMESPACE_USER</code> のみが指定可能です)。
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
- - File#extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) -> array
19
- - File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) -> array
20
- - File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) -> array
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
- - File#extattr_size(name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
25
- - File.extattr_size(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
26
- - File.extattr_size!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
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
- - File#extattr_get(name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
31
- - File.extattr_get(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
32
- - File.extattr_get!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data (String)
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
- - File#extattr_set(name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
37
- - File.extattr_set(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
38
- - File.extattr_set!(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
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
- - File#extattr_delete(name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
43
- - File.extattr_delete(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
44
- - File.extattr_delete!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
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
- 128 KiB を超える ADS は取得も設定も出来ません。これは『拡張属性』と捉えた場合、巨大なデータを扱えるべきではないという考えによるためです (本当のところは FreeBSD の拡張属性が最大 64KiB 弱であることが由来です)。巨大な ADS を扱いたい場合は、File.open で自由に読み書きできます (これは ruby に限ったことではなく、Windows による仕様です)。この場合の与えるファイル名は、path + ":" + name という形になります。
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
- #include <attr/xattr.h>
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
- extattr_list0(ssize_t (*func)(), void *d, int namespace)
20
+ xattr_name(int namespace, VALUE name)
12
21
  {
13
- ssize_t size = 65536;
14
- VALUE buf = rb_str_buf_new(size);
15
- char *ptr = RSTRING_PTR(buf);
16
- size = func(d, ptr, size);
17
- if (size < 0) { rb_sys_fail("listxattr call error"); }
18
-
19
- VALUE (*reduce)(void *, VALUE);
20
- void *first;
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(first, name);
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
- return list;
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
- * ADS は普通のファイルのように扱えるから、extattr とみなして扱う場合は容量の制限を設けることにする。
15
- * ruby-extattr で不十分な巨大なデータを扱う場合は File.open で開くことが出来るので必要であればそちらで。
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
- * TODO: バッファサイズの確保量が結構大きめ。最適化をするべき。
22
- * TODO: CloseHandle してないところがありすぎ。修正。
23
- * TODO: Win9X シリーズだとこのライブラリ読み込みすら出来ない。
24
- * メソッド定義だけは行うようにするべき? (実際に呼び出したら NotImpError 例外を投げる)
25
- * リパースポイントって、ADSはつけられないのかな? 操作方法がわからない。
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
- rb_raise(rb_eSystemCallError, "Win32 API error - %u (%08Xh)", status, status);
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
- if (status != 0) { raise_ntstatus_error(status); }
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 VALUE
167
- extattr_list0(HANDLE file)
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
- if (NIL_P(list)) {
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
- return list;
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
- HANDLE file = CreateFileW(STR2WPATH(path), 0,
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
- HANDLE file = CreateFileW(STR2WPATH(path), 0,
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
- path = rb_str_plus(path, rb_str_new(":", 1));
272
- rb_str_append(path, name);
273
- HANDLE file = CreateFileW(STR2WPATH(path), 0,
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
- path = rb_str_plus(path, rb_str_new(":", 1));
287
- rb_str_append(path, name);
288
- HANDLE file = CreateFileW(STR2WPATH(path), 0,
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
- path = rb_str_plus(path, rb_str_new(":", 1));
320
- rb_str_append(path, name);
321
- HANDLE file = CreateFileW(STR2WPATH(path), GENERIC_READ,
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
- path = rb_str_plus(path, rb_str_new(":", 1));
364
- rb_str_append(path, name);
365
- HANDLE file = CreateFileW(STR2WPATH(path), GENERIC_WRITE,
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
- path = rb_str_plus(path, rb_str_new(":", 1));
386
- rb_str_append(path, name);
387
- DeleteFileW(STR2WPATH(path));
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("file1", "a")
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("file1").should eq([])
35
+ File.extattr_list(filepath).should eq([])
31
36
  end
32
37
 
33
38
  it ".extattr_set" do
34
- File.extattr_set("file1", "ext1", extdata).should nil
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("file1").should eq(["ext1"])
43
+ File.extattr_list(filepath).should eq(["ext1"])
39
44
  end
40
45
 
41
46
  it ".extattr_get" do
42
- File.extattr_get("file1", "ext1").should eq(extdata)
47
+ File.extattr_get(filepath, "ext1").should eq(extdata)
43
48
  end
44
49
 
45
50
  it ".extattr_delete" do
46
- File.extattr_delete("file1", "ext1").should nil
51
+ File.extattr_delete(filepath, "ext1").should nil
47
52
  end
48
53
 
49
54
  it ".extattr_list ((3))" do
50
- File.extattr_list("file1").should eq([])
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: '0.1'
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-02 00:00:00.000000000 Z
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