extattr 0.1.2-x86-mingw32 → 0.2-x86-mingw32
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.
- checksums.yaml +7 -0
- data/{LICENSE.txt → LICENSE.md} +2 -0
- data/README.md +161 -0
- data/Rakefile +105 -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 +227 -102
- data/ext/extconf.rb +14 -12
- data/lib/1.9.1/extattr.so +0 -0
- data/lib/2.0.0/extattr.so +0 -0
- data/lib/2.1.0/extattr.so +0 -0
- data/lib/extattr.rb +47 -0
- data/{rspecs/extattr.rb → spec/extattr_spec.rb} +0 -0
- metadata +54 -31
- data/README.txt +0 -73
- data/ext/extattr.bsd +0 -186
- data/ext/extattr.linux +0 -222
- data/ext/extattr.windows +0 -460
data/ext/extattr.windows
DELETED
@@ -1,460 +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
|
-
#include <ruby/win32.h>
|
10
|
-
|
11
|
-
#define EXTATTR_NAMESPACE_USER 0
|
12
|
-
#define EXTATTR_NAMESPACE_SYSTEM 1
|
13
|
-
|
14
|
-
/*
|
15
|
-
* - TODO:
|
16
|
-
* バッファサイズの確保量が結構大きめ。最適化をするべき。
|
17
|
-
* - TODO:
|
18
|
-
* Win9X シリーズだとこのライブラリ読み込みすら出来ない。
|
19
|
-
* メソッド定義だけは行うようにするべき? (実際に呼び出したら NotImplementedError 例外を投げる、とか)
|
20
|
-
* - リパースポイントって、ADSはつけられないのかな? 操作方法がわからない。
|
21
|
-
*/
|
22
|
-
|
23
|
-
/*
|
24
|
-
* ADS は普通のファイルのように扱えるから、extattr とみなして扱う場合は容量の制限を設けることにする。
|
25
|
-
*
|
26
|
-
* ruby-extattr で不十分な巨大なデータを扱う場合は File.open で開くことが出来るので必要であればそちらで。
|
27
|
-
*
|
28
|
-
* TODO: 最適値を探すべき
|
29
|
-
*/
|
30
|
-
static const size_t EXTATTR_MAX = 65536;
|
31
|
-
|
32
|
-
|
33
|
-
static rb_encoding *ENCutf8p;
|
34
|
-
static VALUE ENCutf8;
|
35
|
-
static rb_encoding *ENCutf16lep;
|
36
|
-
static VALUE ENCutf16le;
|
37
|
-
|
38
|
-
|
39
|
-
static VALUE
|
40
|
-
str2wcs(VALUE str)
|
41
|
-
{
|
42
|
-
str = rb_str_encode(str, ENCutf16le, 0, Qnil);
|
43
|
-
rb_str_buf_cat(str, "\0", 1);
|
44
|
-
return str;
|
45
|
-
}
|
46
|
-
|
47
|
-
static VALUE
|
48
|
-
str2wpath(VALUE str)
|
49
|
-
{
|
50
|
-
str = str2wcs(str);
|
51
|
-
wchar_t *p = (wchar_t *)RSTRING_PTR(str);
|
52
|
-
const wchar_t *end = p + RSTRING_LEN(str) / 2;
|
53
|
-
for (; p < end; p ++) {
|
54
|
-
if (*p == L'/') { *p = L'\\'; }
|
55
|
-
}
|
56
|
-
return str;
|
57
|
-
}
|
58
|
-
|
59
|
-
#define STR2WPATH(str) \
|
60
|
-
({ \
|
61
|
-
(str) = str2wpath(str); \
|
62
|
-
(const wchar_t *)RSTRING_PTR(str); \
|
63
|
-
}) \
|
64
|
-
|
65
|
-
static VALUE
|
66
|
-
wcs2str(const wchar_t str[], size_t size)
|
67
|
-
{
|
68
|
-
if (!str) { return Qnil; }
|
69
|
-
VALUE v = rb_str_new((const char *)str, size * sizeof(str[0]));
|
70
|
-
rb_enc_associate(v, ENCutf16lep);
|
71
|
-
|
72
|
-
return rb_str_encode(v, ENCutf8, ECONV_INVALID_REPLACE | ECONV_UNDEF_REPLACE, Qnil);
|
73
|
-
}
|
74
|
-
|
75
|
-
static VALUE
|
76
|
-
wpath2str(const wchar_t path[], size_t size)
|
77
|
-
{
|
78
|
-
VALUE v = wcs2str(path, size);
|
79
|
-
if (NIL_P(v)) { return Qnil; }
|
80
|
-
char *p = RSTRING_PTR(v);
|
81
|
-
const char *end = p + RSTRING_LEN(v);
|
82
|
-
for (; p < end; p ++) {
|
83
|
-
if (*p == '\\') { *p = '/'; }
|
84
|
-
}
|
85
|
-
return v;
|
86
|
-
}
|
87
|
-
|
88
|
-
/*
|
89
|
-
* ADS 名の先端のコロン『:』と、終端の『:$DATA』を除去してrbuyの文字列を返す。
|
90
|
-
*/
|
91
|
-
static VALUE
|
92
|
-
adsname2str(const wchar_t name[], size_t size)
|
93
|
-
{
|
94
|
-
if (name[0] == L':') {
|
95
|
-
name ++;
|
96
|
-
size --;
|
97
|
-
if (size >= 6 && wcsncmp(name + size - 6, L":$DATA", 6) == 0) {
|
98
|
-
size -= 6;
|
99
|
-
} else {
|
100
|
-
size --;
|
101
|
-
}
|
102
|
-
}
|
103
|
-
|
104
|
-
if (size > 0) {
|
105
|
-
return wpath2str(name, size);
|
106
|
-
} else {
|
107
|
-
return Qnil;
|
108
|
-
}
|
109
|
-
}
|
110
|
-
|
111
|
-
|
112
|
-
static void
|
113
|
-
raise_win32_error(DWORD status, VALUE name)
|
114
|
-
{
|
115
|
-
if (NIL_P(name)) {
|
116
|
-
VALUE args[] = { INT2NUM(rb_w32_map_errno(status)), };
|
117
|
-
rb_exc_raise(rb_class_new_instance(1, args, rb_eSystemCallError));
|
118
|
-
} else {
|
119
|
-
// TODO: name がファイルオブジェクトなのであればパス名を取り出す。パス名がない場合は fd を取り出す。
|
120
|
-
|
121
|
-
VALUE args[] = { StringValue(name), INT2NUM(rb_w32_map_errno(status)), };
|
122
|
-
rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemCallError));
|
123
|
-
}
|
124
|
-
}
|
125
|
-
|
126
|
-
static void
|
127
|
-
raise_ntstatus_error(NTSTATUS status, VALUE name)
|
128
|
-
{
|
129
|
-
raise_win32_error(RtlNtStatusToDosError(status), name);
|
130
|
-
}
|
131
|
-
|
132
|
-
static void
|
133
|
-
check_status_error(NTSTATUS status)
|
134
|
-
{
|
135
|
-
if (status != STATUS_SUCCESS) {
|
136
|
-
raise_ntstatus_error(status, Qnil);
|
137
|
-
}
|
138
|
-
}
|
139
|
-
|
140
|
-
|
141
|
-
static VALUE
|
142
|
-
get_filepath(HANDLE file)
|
143
|
-
{
|
144
|
-
DWORD size = 65536;
|
145
|
-
VALUE buf = rb_str_buf_new(size);
|
146
|
-
NTSTATUS status = NtQueryObject(file,
|
147
|
-
ObjectNameInformation,
|
148
|
-
RSTRING_PTR(buf),
|
149
|
-
size,
|
150
|
-
&size);
|
151
|
-
check_status_error(status);
|
152
|
-
|
153
|
-
const OBJECT_NAME_INFORMATION *info = (const OBJECT_NAME_INFORMATION *)RSTRING_PTR(buf);
|
154
|
-
if (wcsnicmp(info->Name.Buffer, L"\\Device\\", 8) == 0) {
|
155
|
-
// 先頭の "/Device/" を "//?/" に置き換える
|
156
|
-
wcsncpy(info->Name.Buffer + 4, L"\\\\?\\", 4);
|
157
|
-
return wpath2str(info->Name.Buffer + 4, info->Name.Length / 2 - 4);
|
158
|
-
} else {
|
159
|
-
return wpath2str(info->Name.Buffer, info->Name.Length / 2);
|
160
|
-
}
|
161
|
-
}
|
162
|
-
|
163
|
-
static uint64_t
|
164
|
-
get_filesize(HANDLE file)
|
165
|
-
{
|
166
|
-
BY_HANDLE_FILE_INFORMATION info;
|
167
|
-
|
168
|
-
if (!GetFileInformationByHandle(file, &info)) {
|
169
|
-
raise_win32_error(GetLastError(), Qnil);
|
170
|
-
}
|
171
|
-
|
172
|
-
return ((uint64_t)info.nFileSizeHigh << 32) | info.nFileSizeLow;
|
173
|
-
}
|
174
|
-
|
175
|
-
static VALUE
|
176
|
-
file_close(HANDLE file)
|
177
|
-
{
|
178
|
-
/*
|
179
|
-
* rb_ensure から直接呼びたかったけど、呼び出し規約が違うから無理だよね。
|
180
|
-
*/
|
181
|
-
CloseHandle(file);
|
182
|
-
|
183
|
-
return Qnil;
|
184
|
-
}
|
185
|
-
|
186
|
-
static void
|
187
|
-
check_namespace(int namespace, VALUE path)
|
188
|
-
{
|
189
|
-
if (namespace != EXTATTR_NAMESPACE_USER) {
|
190
|
-
errno = EPERM;
|
191
|
-
if (NIL_P(path)) {
|
192
|
-
rb_sys_fail(NULL);
|
193
|
-
} else {
|
194
|
-
rb_sys_fail(StringValueCStr(path));
|
195
|
-
}
|
196
|
-
}
|
197
|
-
}
|
198
|
-
|
199
|
-
|
200
|
-
static void
|
201
|
-
extattr_list_name(const char *ptr, void *(*yield)(void *user, VALUE name), void *user)
|
202
|
-
{
|
203
|
-
for (;;) {
|
204
|
-
const FILE_STREAM_INFORMATION *info = (const FILE_STREAM_INFORMATION *)ptr;
|
205
|
-
VALUE name = adsname2str(info->StreamName, info->StreamNameLength / 2);
|
206
|
-
if (!NIL_P(name) && RSTRING_LEN(name) > 0) {
|
207
|
-
yield(user, name);
|
208
|
-
}
|
209
|
-
size_t size = info->NextEntryOffset;
|
210
|
-
if (size == 0) { break; }
|
211
|
-
ptr += size;
|
212
|
-
}
|
213
|
-
}
|
214
|
-
|
215
|
-
static VALUE
|
216
|
-
extattr_list0_try(HANDLE file)
|
217
|
-
{
|
218
|
-
VALUE iostatusblock = rb_str_buf_new(4096);
|
219
|
-
size_t size = 65536; // TODO: 最適値を見つける
|
220
|
-
VALUE infobuf = rb_str_buf_new(size);
|
221
|
-
char *ptr = RSTRING_PTR(infobuf);
|
222
|
-
memset(ptr, 0, sizeof(FILE_STREAM_INFORMATION));
|
223
|
-
NTSTATUS status = NtQueryInformationFile(file,
|
224
|
-
(PIO_STATUS_BLOCK)RSTRING_PTR(iostatusblock),
|
225
|
-
ptr, size,
|
226
|
-
FileStreamInformation);
|
227
|
-
check_status_error(status);
|
228
|
-
|
229
|
-
if (rb_block_given_p()) {
|
230
|
-
extattr_list_name(ptr,
|
231
|
-
(void *(*)(void *, VALUE))rb_yield_values,
|
232
|
-
(void *)1);
|
233
|
-
return Qnil;
|
234
|
-
} else {
|
235
|
-
VALUE list = rb_ary_new();
|
236
|
-
extattr_list_name(ptr,
|
237
|
-
(void *(*)(void *, VALUE))rb_ary_push,
|
238
|
-
(void *)list);
|
239
|
-
return list;
|
240
|
-
}
|
241
|
-
}
|
242
|
-
|
243
|
-
static VALUE
|
244
|
-
extattr_list0(VALUE path, DWORD flags, int namespace)
|
245
|
-
{
|
246
|
-
check_namespace(namespace, path);
|
247
|
-
VALUE path1 = path;
|
248
|
-
HANDLE file = CreateFileW(STR2WPATH(path1), 0,
|
249
|
-
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
250
|
-
NULL, 3,
|
251
|
-
FILE_FLAG_BACKUP_SEMANTICS | flags,
|
252
|
-
0);
|
253
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
254
|
-
return rb_ensure(extattr_list0_try, (VALUE)file, file_close, (VALUE)file);
|
255
|
-
}
|
256
|
-
|
257
|
-
static VALUE
|
258
|
-
file_extattr_list0(VALUE file, int fd, int namespace)
|
259
|
-
{
|
260
|
-
check_namespace(namespace, Qnil);
|
261
|
-
HANDLE file1 = (HANDLE)_get_osfhandle(fd);
|
262
|
-
return extattr_list0_try(file1);
|
263
|
-
}
|
264
|
-
|
265
|
-
static VALUE
|
266
|
-
file_s_extattr_list0(VALUE path, int namespace)
|
267
|
-
{
|
268
|
-
return extattr_list0(path, 0, namespace);
|
269
|
-
}
|
270
|
-
|
271
|
-
static VALUE
|
272
|
-
file_s_extattr_list_link0(VALUE path, int namespace)
|
273
|
-
{
|
274
|
-
return extattr_list0(path, FILE_FLAG_OPEN_REPARSE_POINT, namespace);
|
275
|
-
}
|
276
|
-
|
277
|
-
|
278
|
-
static VALUE
|
279
|
-
extattr_size0_try(HANDLE file)
|
280
|
-
{
|
281
|
-
return ULL2NUM(get_filesize(file));
|
282
|
-
}
|
283
|
-
|
284
|
-
static VALUE
|
285
|
-
extattr_size0(VALUE path, DWORD flags, int namespace, VALUE name)
|
286
|
-
{
|
287
|
-
check_namespace(namespace, path);
|
288
|
-
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
289
|
-
rb_str_append(path1, name);
|
290
|
-
HANDLE file = CreateFileW(STR2WPATH(path1), 0,
|
291
|
-
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
292
|
-
NULL, 3,
|
293
|
-
FILE_FLAG_BACKUP_SEMANTICS | flags,
|
294
|
-
0);
|
295
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
296
|
-
return rb_ensure(extattr_size0_try, (VALUE)file, file_close, (VALUE)file);
|
297
|
-
}
|
298
|
-
|
299
|
-
static VALUE
|
300
|
-
file_extattr_size0(VALUE file, int fd, int namespace, VALUE name)
|
301
|
-
{
|
302
|
-
return file_s_extattr_size0(get_filepath((HANDLE)_get_osfhandle(fd)),
|
303
|
-
namespace, name);
|
304
|
-
}
|
305
|
-
|
306
|
-
static VALUE
|
307
|
-
file_s_extattr_size0(VALUE path, int namespace, VALUE name)
|
308
|
-
{
|
309
|
-
return extattr_size0(path, 0, namespace, name);
|
310
|
-
}
|
311
|
-
|
312
|
-
static VALUE
|
313
|
-
file_s_extattr_size_link0(VALUE path, int namespace, VALUE name)
|
314
|
-
{
|
315
|
-
return extattr_size0(path, FILE_FLAG_OPEN_REPARSE_POINT, namespace, name);
|
316
|
-
}
|
317
|
-
|
318
|
-
|
319
|
-
static VALUE
|
320
|
-
extattr_get_try(VALUE args[3])
|
321
|
-
{
|
322
|
-
HANDLE file = (HANDLE)args[0];
|
323
|
-
int namespace = (int)args[1];
|
324
|
-
VALUE name = args[2];
|
325
|
-
uint64_t size = get_filesize(file);
|
326
|
-
if (size > EXTATTR_MAX) { rb_raise(rb_eSystemCallError, "extattr too huge"); }
|
327
|
-
VALUE buf = rb_str_buf_new(size);
|
328
|
-
DWORD readsize = 0;
|
329
|
-
if (!ReadFile(file, RSTRING_PTR(buf), size, &readsize, NULL)) {
|
330
|
-
raise_win32_error(GetLastError(), Qnil);
|
331
|
-
}
|
332
|
-
rb_str_set_len(buf, readsize);
|
333
|
-
return buf;
|
334
|
-
}
|
335
|
-
|
336
|
-
static VALUE
|
337
|
-
extattr_get0(VALUE path, int flags, int namespace, VALUE name)
|
338
|
-
{
|
339
|
-
check_namespace(namespace, path);
|
340
|
-
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
341
|
-
rb_str_append(path1, name);
|
342
|
-
HANDLE file = CreateFileW(STR2WPATH(path1), GENERIC_READ,
|
343
|
-
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
344
|
-
NULL, 3,
|
345
|
-
FILE_FLAG_BACKUP_SEMANTICS | flags,
|
346
|
-
0);
|
347
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
348
|
-
VALUE args[] = { (VALUE)file, (VALUE)namespace, name, };
|
349
|
-
return rb_ensure(extattr_get_try, (VALUE)args, file_close, (VALUE)file);
|
350
|
-
}
|
351
|
-
|
352
|
-
static VALUE
|
353
|
-
file_extattr_get0(VALUE file, int fd, int namespace, VALUE name)
|
354
|
-
{
|
355
|
-
return file_s_extattr_get0(get_filepath((HANDLE)_get_osfhandle(fd)),
|
356
|
-
namespace, name);
|
357
|
-
}
|
358
|
-
|
359
|
-
static VALUE
|
360
|
-
file_s_extattr_get0(VALUE path, int namespace, VALUE name)
|
361
|
-
{
|
362
|
-
return extattr_get0(path, 0, namespace, name);
|
363
|
-
}
|
364
|
-
|
365
|
-
static VALUE
|
366
|
-
file_s_extattr_get_link0(VALUE path, int namespace, VALUE name)
|
367
|
-
{
|
368
|
-
return extattr_get0(path, FILE_FLAG_OPEN_REPARSE_POINT, namespace, name);
|
369
|
-
}
|
370
|
-
|
371
|
-
|
372
|
-
static VALUE
|
373
|
-
extattr_set0_try(VALUE args[])
|
374
|
-
{
|
375
|
-
HANDLE file = (HANDLE)args[0];
|
376
|
-
int namespace = (int)args[1];
|
377
|
-
VALUE name = (VALUE)args[2];
|
378
|
-
VALUE data = (VALUE)args[3];
|
379
|
-
uint64_t size = RSTRING_LEN(data);
|
380
|
-
if (size > EXTATTR_MAX) { rb_raise(rb_eSystemCallError, "extattr too huge"); }
|
381
|
-
DWORD wrotesize = size;
|
382
|
-
if (!WriteFile(file, RSTRING_PTR(data), size, &wrotesize, NULL)) {
|
383
|
-
raise_win32_error(GetLastError(), Qnil);
|
384
|
-
}
|
385
|
-
return Qnil;
|
386
|
-
}
|
387
|
-
|
388
|
-
static VALUE
|
389
|
-
extattr_set0(VALUE path, DWORD flags, int namespace, VALUE name, VALUE data)
|
390
|
-
{
|
391
|
-
check_namespace(namespace, path);
|
392
|
-
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
393
|
-
rb_str_append(path1, name);
|
394
|
-
HANDLE file = CreateFileW(STR2WPATH(path1), GENERIC_WRITE,
|
395
|
-
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
396
|
-
NULL, CREATE_ALWAYS,
|
397
|
-
FILE_FLAG_BACKUP_SEMANTICS | flags,
|
398
|
-
0);
|
399
|
-
if (file == INVALID_HANDLE_VALUE) { raise_win32_error(GetLastError(), path); }
|
400
|
-
VALUE args[] = { (VALUE)file, (VALUE)namespace, name, data };
|
401
|
-
return rb_ensure(extattr_set0_try, (VALUE)args, file_close, (VALUE)file);
|
402
|
-
}
|
403
|
-
|
404
|
-
static VALUE
|
405
|
-
file_extattr_set0(VALUE file, int fd, int namespace, VALUE name, VALUE data)
|
406
|
-
{
|
407
|
-
return file_s_extattr_set0(get_filepath((HANDLE)_get_osfhandle(fd)),
|
408
|
-
namespace, name, data);
|
409
|
-
}
|
410
|
-
|
411
|
-
static VALUE
|
412
|
-
file_s_extattr_set0(VALUE path, int namespace, VALUE name, VALUE data)
|
413
|
-
{
|
414
|
-
return extattr_set0(path, 0, namespace, name, data);
|
415
|
-
}
|
416
|
-
|
417
|
-
static VALUE
|
418
|
-
file_s_extattr_set_link0(VALUE path, int namespace, VALUE name, VALUE data)
|
419
|
-
{
|
420
|
-
return extattr_set0(path, FILE_FLAG_OPEN_REPARSE_POINT, namespace, name, data);
|
421
|
-
}
|
422
|
-
|
423
|
-
|
424
|
-
static VALUE
|
425
|
-
file_extattr_delete0(VALUE file, int fd, int namespace, VALUE name)
|
426
|
-
{
|
427
|
-
return file_s_extattr_delete0(get_filepath((HANDLE)_get_osfhandle(fd)),
|
428
|
-
namespace, name);
|
429
|
-
}
|
430
|
-
|
431
|
-
static VALUE
|
432
|
-
file_s_extattr_delete0(VALUE path, int namespace, VALUE name)
|
433
|
-
{
|
434
|
-
check_namespace(namespace, path);
|
435
|
-
VALUE path1 = rb_str_plus(path, rb_str_new(":", 1));
|
436
|
-
rb_str_append(path1, name);
|
437
|
-
if (!DeleteFileW(STR2WPATH(path1))) {
|
438
|
-
raise_win32_error(GetLastError(), path);
|
439
|
-
}
|
440
|
-
return Qnil;
|
441
|
-
}
|
442
|
-
|
443
|
-
static VALUE
|
444
|
-
file_s_extattr_delete_link0(VALUE path, int namespace, VALUE name)
|
445
|
-
{
|
446
|
-
return file_s_extattr_delete0(path, namespace, name);
|
447
|
-
}
|
448
|
-
|
449
|
-
|
450
|
-
static void
|
451
|
-
setup(void)
|
452
|
-
{
|
453
|
-
ENCutf8p = rb_enc_find("UTF-8");
|
454
|
-
ENCutf8 = rb_enc_from_encoding(ENCutf8p);
|
455
|
-
rb_gc_register_address(&ENCutf8);
|
456
|
-
|
457
|
-
ENCutf16lep = rb_enc_find("UTF-16LE");
|
458
|
-
ENCutf16le = rb_enc_from_encoding(ENCutf16lep);
|
459
|
-
rb_gc_register_address(&ENCutf16le);
|
460
|
-
}
|