extattr 0.1 → 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/ext/extattr.windows DELETED
@@ -1,407 +0,0 @@
1
- #include <windows.h>
2
- #include <windowsx.h>
3
- #include <winnt.h>
4
- #include <ddk/ntifs.h>
5
- #include <ddk/winddk.h>
6
- #include <ntdef.h>
7
- #include <psapi.h>
8
- #include <wchar.h>
9
-
10
- #define EXTATTR_NAMESPACE_USER 0
11
- #define EXTATTR_NAMESPACE_SYSTEM 1
12
-
13
- /*
14
- * ADS は普通のファイルのように扱えるから、extattr とみなして扱う場合は容量の制限を設けることにする。
15
- * ruby-extattr で不十分な巨大なデータを扱う場合は File.open で開くことが出来るので必要であればそちらで。
16
- * TODO: 最適値を探すべき
17
- */
18
- static const size_t EXTATTR_MAX = 131072;
19
-
20
- /*
21
- * TODO: バッファサイズの確保量が結構大きめ。最適化をするべき。
22
- * TODO: CloseHandle してないところがありすぎ。修正。
23
- * TODO: Win9X シリーズだとこのライブラリ読み込みすら出来ない。
24
- * メソッド定義だけは行うようにするべき? (実際に呼び出したら NotImpError 例外を投げる)
25
- * リパースポイントって、ADSはつけられないのかな? 操作方法がわからない。
26
- */
27
-
28
-
29
- static rb_encoding *ENCutf8p;
30
- static VALUE ENCutf8;
31
- static rb_encoding *ENCutf16lep;
32
- static VALUE ENCutf16le;
33
-
34
-
35
-
36
-
37
- static VALUE
38
- str2wcs(VALUE str)
39
- {
40
- str = rb_str_encode(str, ENCutf16le, 0, Qnil);
41
- rb_str_buf_cat(str, "\0", 1);
42
- return str;
43
- }
44
-
45
- static VALUE
46
- str2wpath(VALUE str)
47
- {
48
- str = str2wcs(str);
49
- wchar_t *p = (wchar_t *)RSTRING_PTR(str);
50
- const wchar_t *end = p + RSTRING_LEN(str) / 2;
51
- for (; p < end; p ++) {
52
- if (*p == L'/') { *p = L'\\'; }
53
- }
54
- return str;
55
- }
56
-
57
- #define STR2WPATH(str) \
58
- ({ \
59
- (str) = str2wpath(str); \
60
- (const wchar_t *)RSTRING_PTR(str); \
61
- }) \
62
-
63
-
64
- static VALUE
65
- wcs2str(const wchar_t str[], size_t size)
66
- {
67
- if (!str) { return Qnil; }
68
- VALUE v = rb_str_new((const char *)str, size * sizeof(str[0]));
69
- rb_enc_associate(v, ENCutf16lep);
70
-
71
- return rb_str_encode(v, ENCutf8, ECONV_INVALID_REPLACE | ECONV_UNDEF_REPLACE, Qnil);
72
- }
73
-
74
- static VALUE
75
- wpath2str(const wchar_t path[], size_t size)
76
- {
77
- VALUE v = wcs2str(path, size);
78
- if (NIL_P(v)) { return Qnil; }
79
- char *p = RSTRING_PTR(v);
80
- const char *end = p + RSTRING_LEN(v);
81
- for (; p < end; p ++) {
82
- if (*p == '\\') { *p = '/'; }
83
- }
84
- return v;
85
- }
86
-
87
- /*
88
- * ADS 名の先端のコロン『:』と、終端の『:$DATA』を除去してrbuyの文字列を返す。
89
- */
90
- static VALUE
91
- adsname2str(const wchar_t name[], size_t size)
92
- {
93
- if (name[0] == L':' && wcsncmp(name + size - 6, L":$DATA", 6) == 0) {
94
- name += 1;
95
- size -= 7;
96
- }
97
-
98
- return wpath2str(name, size);
99
- }
100
-
101
-
102
- static void
103
- raise_win32_error(DWORD status)
104
- {
105
- rb_raise(rb_eSystemCallError, "Win32 API error - %u (%08Xh)", status, status);
106
- }
107
-
108
- static void
109
- raise_ntstatus_error(NTSTATUS status)
110
- {
111
- rb_raise(rb_eSystemCallError, "NTSTATUS error - %u (%08Xh)", status, status);
112
- }
113
-
114
- static VALUE
115
- get_filepath(HANDLE file)
116
- {
117
- DWORD size = 65536;
118
- VALUE buf = rb_str_buf_new(size);
119
- NTSTATUS status = NtQueryObject(file,
120
- ObjectNameInformation,
121
- RSTRING_PTR(buf),
122
- size,
123
- &size);
124
- if (status != 0) { raise_ntstatus_error(status); }
125
- const OBJECT_NAME_INFORMATION *info = (const OBJECT_NAME_INFORMATION *)RSTRING_PTR(buf);
126
- if (wcsnicmp(info->Name.Buffer, L"\\Device\\", 8) == 0) {
127
- // 先頭の "/Device/" を "//?/" に置き換える
128
- wcsncpy(info->Name.Buffer + 4, L"\\\\?\\", 4);
129
- return wpath2str(info->Name.Buffer + 4, info->Name.Length / 2 - 4);
130
- } else {
131
- return wpath2str(info->Name.Buffer, info->Name.Length / 2);
132
- }
133
- }
134
-
135
- static uint64_t
136
- get_filesize(HANDLE file)
137
- {
138
- BY_HANDLE_FILE_INFORMATION info;
139
-
140
- if (!GetFileInformationByHandle(file, &info)) {
141
- raise_win32_error(GetLastError());
142
- }
143
-
144
- return ((uint64_t)info.nFileSizeHigh << 32) | info.nFileSizeLow;
145
- }
146
-
147
- static VALUE
148
- file_close(HANDLE file)
149
- {
150
- /*
151
- * rb_ensure から直接呼びたかったけど、呼び出し規約が違うから無理だよね。
152
- */
153
- CloseHandle(file);
154
- }
155
-
156
- static void
157
- check_namespace(int namespace)
158
- {
159
- if (namespace != EXTATTR_NAMESPACE_USER) {
160
- errno = EPERM;
161
- rb_sys_fail(NULL);
162
- }
163
- }
164
-
165
-
166
- static VALUE
167
- extattr_list0(HANDLE file)
168
- {
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
- for (;;) {
181
- const FILE_STREAM_INFORMATION *info = (const FILE_STREAM_INFORMATION *)ptr;
182
- VALUE name = adsname2str(info->StreamName, info->StreamNameLength / 2);
183
- if (RSTRING_LEN(name) > 0) {
184
- if (NIL_P(list)) {
185
- rb_yield(name);
186
- } else {
187
- rb_ary_push(list, name);
188
- }
189
- }
190
- size_t size = info->NextEntryOffset;
191
- if (size == 0) { break; }
192
- ptr += size;
193
- }
194
- return list;
195
- }
196
-
197
- static VALUE
198
- extattr_size0(HANDLE file)
199
- {
200
- return ULL2NUM(get_filesize(file));
201
- }
202
-
203
-
204
- static VALUE
205
- file_extattr_list0(VALUE file, int fd, int namespace)
206
- {
207
- check_namespace(namespace);
208
- HANDLE file1 = (HANDLE)_get_osfhandle(fd);
209
- return extattr_list0(file1);
210
- }
211
-
212
- static VALUE
213
- file_extattr_size0(VALUE file, int fd, int namespace, VALUE name)
214
- {
215
- return file_s_extattr_size0(get_filepath((HANDLE)_get_osfhandle(fd)),
216
- namespace, name);
217
- }
218
-
219
- static VALUE
220
- file_extattr_get0(VALUE file, int fd, int namespace, VALUE name)
221
- {
222
- return file_s_extattr_get0(get_filepath((HANDLE)_get_osfhandle(fd)),
223
- namespace, name);
224
- }
225
-
226
- static VALUE
227
- file_extattr_set0(VALUE file, int fd, int namespace, VALUE name, VALUE data)
228
- {
229
- return file_s_extattr_set0(get_filepath((HANDLE)_get_osfhandle(fd)),
230
- namespace, name, data);
231
- }
232
-
233
- static VALUE
234
- file_extattr_delete0(VALUE file, int fd, int namespace, VALUE name)
235
- {
236
- return file_s_extattr_delete0(get_filepath((HANDLE)_get_osfhandle(fd)),
237
- namespace, name);
238
- }
239
-
240
-
241
- static VALUE
242
- file_s_extattr_list0(VALUE path, int namespace)
243
- {
244
- check_namespace(namespace);
245
- HANDLE file = CreateFileW(STR2WPATH(path), 0,
246
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
247
- NULL, 3,
248
- FILE_FLAG_BACKUP_SEMANTICS,
249
- 0);
250
- if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
251
- return rb_ensure(extattr_list0, (VALUE)file, file_close, (VALUE)file);
252
- }
253
-
254
- static VALUE
255
- file_s_extattr_list_link0(VALUE path, int namespace)
256
- {
257
- check_namespace(namespace);
258
- HANDLE file = CreateFileW(STR2WPATH(path), 0,
259
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
260
- NULL, 3,
261
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
262
- 0);
263
- if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
264
- return rb_ensure(extattr_list0, (VALUE)file, file_close, (VALUE)file);
265
- }
266
-
267
- static VALUE
268
- file_s_extattr_size0(VALUE path, int namespace, VALUE name)
269
- {
270
- 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,
274
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
275
- NULL, 3,
276
- FILE_FLAG_BACKUP_SEMANTICS,
277
- 0);
278
- if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
279
- return rb_ensure(extattr_size0, (VALUE)file, file_close, (VALUE)file);
280
- }
281
-
282
- static VALUE
283
- file_s_extattr_size_link0(VALUE path, int namespace, VALUE name)
284
- {
285
- 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,
289
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
290
- NULL, 3,
291
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
292
- 0);
293
- if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
294
- return rb_ensure(extattr_size0, (VALUE)file, file_close, (VALUE)file);
295
- }
296
-
297
-
298
- static VALUE
299
- extattr_get0(VALUE args[3])
300
- {
301
- HANDLE file = (HANDLE)args[0];
302
- int namespace = (int)args[1];
303
- VALUE name = args[2];
304
- uint64_t size = get_filesize(file);
305
- if (size > EXTATTR_MAX) { rb_raise(rb_eSystemCallError, "extattr too huge"); }
306
- VALUE buf = rb_str_buf_new(size);
307
- DWORD readsize = 0;
308
- if (!ReadFile(file, RSTRING_PTR(buf), size, &readsize, NULL)) {
309
- raise_win32_error(GetLastError());
310
- }
311
- rb_str_set_len(buf, readsize);
312
- return buf;
313
- }
314
-
315
- static VALUE
316
- extattr_get1(VALUE path, int flags, int namespace, VALUE name)
317
- {
318
- 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,
322
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
323
- NULL, 3,
324
- FILE_FLAG_BACKUP_SEMANTICS | flags,
325
- 0);
326
- if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
327
- VALUE args[] = { (VALUE)file, (VALUE)namespace, name, };
328
- return rb_ensure(extattr_get0, (VALUE)args, file_close, (VALUE)file);
329
- }
330
-
331
- static VALUE
332
- file_s_extattr_get0(VALUE path, int namespace, VALUE name)
333
- {
334
- return extattr_get1(path, 0, namespace, name);
335
- }
336
-
337
- static VALUE
338
- file_s_extattr_get_link0(VALUE path, int namespace, VALUE name)
339
- {
340
- return extattr_get1(path, FILE_FLAG_OPEN_REPARSE_POINT, namespace, name);
341
- }
342
-
343
- static VALUE
344
- extattr_set0(VALUE args[])
345
- {
346
- HANDLE file = (HANDLE)args[0];
347
- int namespace = (int)args[1];
348
- VALUE name = (VALUE)args[2];
349
- VALUE data = (VALUE)args[3];
350
- uint64_t size = RSTRING_LEN(data);
351
- if (size > EXTATTR_MAX) { rb_raise(rb_eSystemCallError, "extattr too huge"); }
352
- DWORD wrotesize = size;
353
- if (!WriteFile(file, RSTRING_PTR(data), size, &wrotesize, NULL)) {
354
- raise_win32_error(GetLastError());
355
- }
356
- return Qnil;
357
- }
358
-
359
- static VALUE
360
- file_s_extattr_set0(VALUE path, int namespace, VALUE name, VALUE data)
361
- {
362
- 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,
366
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
367
- NULL, CREATE_ALWAYS,
368
- FILE_FLAG_BACKUP_SEMANTICS,
369
- 0);
370
- if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError()); }
371
- VALUE args[] = { (VALUE)file, (VALUE)namespace, name, data };
372
- return rb_ensure(extattr_set0, (VALUE)args, file_close, (VALUE)file);
373
- }
374
-
375
- static VALUE
376
- file_s_extattr_set_link0(VALUE path, int namespace, VALUE name, VALUE data)
377
- {
378
- return file_s_extattr_set0(path, namespace, name, data);
379
- }
380
-
381
- static VALUE
382
- file_s_extattr_delete0(VALUE path, int namespace, VALUE name)
383
- {
384
- check_namespace(namespace);
385
- path = rb_str_plus(path, rb_str_new(":", 1));
386
- rb_str_append(path, name);
387
- DeleteFileW(STR2WPATH(path));
388
- return Qnil;
389
- }
390
-
391
- static VALUE
392
- file_s_extattr_delete_link0(VALUE path, int namespace, VALUE name)
393
- {
394
- return file_s_extattr_delete0(path, namespace, name);
395
- }
396
-
397
- static void
398
- setup(void)
399
- {
400
- ENCutf8p = rb_enc_find("UTF-8");
401
- ENCutf8 = rb_enc_from_encoding(ENCutf8p);
402
- rb_gc_register_address(&ENCutf8);
403
-
404
- ENCutf16lep = rb_enc_find("UTF-16LE");
405
- ENCutf16le = rb_enc_from_encoding(ENCutf16lep);
406
- rb_gc_register_address(&ENCutf16le);
407
- }
data/rspecs/extattr.rb DELETED
@@ -1,53 +0,0 @@
1
- #vim: set fileencoding:utf-8
2
-
3
- require "tmpdir"
4
- basedir = File.join(Dir.tmpdir, "ruby-extattr.test-work")
5
- Dir.mkdir basedir unless File.directory? basedir
6
-
7
- require "extattr"
8
-
9
- extdata = "abcdefg"
10
-
11
- Dir.chdir basedir do
12
- describe "file" do
13
- file = nil
14
- before(:all) do
15
- file = File.open("file1", "a")
16
- end
17
-
18
- it ".extattr_list" do
19
- file.extattr_list.should eq([])
20
- end
21
-
22
- after(:all) do
23
- file.close
24
- file = nil
25
- end
26
- end
27
-
28
- describe File do
29
- it ".extattr_list" do
30
- File.extattr_list("file1").should eq([])
31
- end
32
-
33
- it ".extattr_set" do
34
- File.extattr_set("file1", "ext1", extdata).should nil
35
- end
36
-
37
- it ".extattr_list ((2))" do
38
- File.extattr_list("file1").should eq(["ext1"])
39
- end
40
-
41
- it ".extattr_get" do
42
- File.extattr_get("file1", "ext1").should eq(extdata)
43
- end
44
-
45
- it ".extattr_delete" do
46
- File.extattr_delete("file1", "ext1").should nil
47
- end
48
-
49
- it ".extattr_list ((3))" do
50
- File.extattr_list("file1").should eq([])
51
- end
52
- end
53
- end