extattr 0.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
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