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.
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
- }