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.c CHANGED
@@ -2,40 +2,52 @@
2
2
 
3
3
  /*
4
4
  * extattr.c
5
- * AUTHOR:: dearblue <dearblue@zoho.com>
5
+ * AUTHOR:: dearblue <dearblue@users.osdn.me>
6
6
  * LICENSE:: 2-clause BSD License
7
- * WWW:: http://sourceforge.jp/projects/rutsubo
7
+ * PROJECT-PAGE:: https://github.com/dearblue/ruby-extattr
8
8
  */
9
9
 
10
10
  #include <ruby.h>
11
11
  #include <ruby/io.h>
12
12
  #include <ruby/intern.h>
13
-
14
-
15
- static VALUE file_extattr_list0(VALUE file, int fd, int namespace);
16
- static VALUE file_extattr_size0(VALUE file, int fd, int namespace, VALUE name);
17
- static VALUE file_extattr_get0(VALUE file, int fd, int namespace, VALUE name);
18
- static VALUE file_extattr_set0(VALUE file, int fd, int namespace, VALUE name, VALUE data);
19
- static VALUE file_extattr_delete0(VALUE file, int fd, int namespace, VALUE name);
20
- static VALUE file_s_extattr_list0(VALUE path, int namespace);
21
- static VALUE file_s_extattr_list_link0(VALUE path, int namespace);
22
- static VALUE file_s_extattr_size0(VALUE path, int namespace, VALUE name);
23
- static VALUE file_s_extattr_size_link0(VALUE path, int namespace, VALUE name);
24
- static VALUE file_s_extattr_get0(VALUE path, int namespace, VALUE name);
25
- static VALUE file_s_extattr_get_link0(VALUE path, int namespace, VALUE name);
26
- static VALUE file_s_extattr_set0(VALUE path, int namespace, VALUE name, VALUE data);
27
- static VALUE file_s_extattr_set_link0(VALUE path, int namespace, VALUE name, VALUE data);
28
- static VALUE file_s_extattr_delete0(VALUE path, int namespace, VALUE name);
29
- static VALUE file_s_extattr_delete_link0(VALUE path, int namespace, VALUE name);
13
+ #include <ruby/version.h>
14
+ #include <ctype.h>
15
+
16
+
17
+ static VALUE file_extattr_list_main(VALUE file, int fd, int namespace1);
18
+ static VALUE file_extattr_size_main(VALUE file, int fd, int namespace1, VALUE name);
19
+ static VALUE file_extattr_get_main(VALUE file, int fd, int namespace1, VALUE name);
20
+ static VALUE file_extattr_set_main(VALUE file, int fd, int namespace1, VALUE name, VALUE data);
21
+ static VALUE file_extattr_delete_main(VALUE file, int fd, int namespace1, VALUE name);
22
+ static VALUE file_s_extattr_list_main(VALUE path, int namespace1);
23
+ static VALUE file_s_extattr_list_link_main(VALUE path, int namespace1);
24
+ static VALUE file_s_extattr_size_main(VALUE path, int namespace1, VALUE name);
25
+ static VALUE file_s_extattr_size_link_main(VALUE path, int namespace1, VALUE name);
26
+ static VALUE file_s_extattr_get_main(VALUE path, int namespace1, VALUE name);
27
+ static VALUE file_s_extattr_get_link_main(VALUE path, int namespace1, VALUE name);
28
+ static VALUE file_s_extattr_set_main(VALUE path, int namespace1, VALUE name, VALUE data);
29
+ static VALUE file_s_extattr_set_link_main(VALUE path, int namespace1, VALUE name, VALUE data);
30
+ static VALUE file_s_extattr_delete_main(VALUE path, int namespace1, VALUE name);
31
+ static VALUE file_s_extattr_delete_link_main(VALUE path, int namespace1, VALUE name);
30
32
 
31
33
  // Init_extattr から呼び出される、環境ごとの初期設定。
32
- static void setup(void);
34
+ static void extattr_init_implement(void);
33
35
 
36
+ #if RUBY_API_VERSION_CODE >= 20700
37
+ # define rb_obj_infect(OBJ, SRC) ((void)0)
38
+ #endif
34
39
 
35
40
  #define RDOC(...)
36
41
 
37
42
  #define ELEMENTOF(V) (sizeof(V) / sizeof((V)[0]))
38
43
 
44
+ #define LOGF(FORMAT, ...) { fprintf(stderr, "%s:%d:%s: " FORMAT "\n", __FILE__, __LINE__, __func__, __VA_ARGS__); }
45
+
46
+ static VALUE mExtAttr;
47
+
48
+ static ID id_downcase;
49
+ static ID id_to_path;
50
+
39
51
 
40
52
  static inline VALUE
41
53
  hash_lookup(VALUE hash, VALUE key, VALUE default_value)
@@ -52,294 +64,469 @@ hash_lookup(VALUE hash, VALUE key, VALUE default_value)
52
64
  static inline int
53
65
  file2fd(VALUE file)
54
66
  {
67
+ rb_check_type(file, RUBY_T_FILE);
55
68
  rb_io_t *fptr;
56
- // FIXME: ファイルであることを確認すべき
57
69
  GetOpenFile(file, fptr);
58
70
  return fptr->fd;
59
71
  }
60
72
 
73
+ static inline void
74
+ ext_error_extattr(int err, VALUE filepath, VALUE attrname)
75
+ {
76
+ errno = err;
77
+ if (NIL_P(filepath)) {
78
+ filepath = rb_str_new_cstr("<?>");
79
+ } else {
80
+ filepath = rb_get_path_no_checksafe(filepath);
81
+ }
82
+ VALUE mesg = rb_sprintf("%s [%s]", StringValueCStr(filepath), StringValueCStr(attrname));
83
+ rb_sys_fail(StringValueCStr(mesg));
84
+ }
85
+
86
+ static inline void
87
+ ext_error_namespace(VALUE path, int namespace1)
88
+ {
89
+ ext_error_extattr(EPERM, path, rb_sprintf("namespace=%d", namespace1));
90
+ }
91
+
92
+ static VALUE
93
+ aux_to_path(VALUE path)
94
+ {
95
+ if (rb_respond_to(path, id_to_path)) {
96
+ VALUE args[] = { path };
97
+ path = rb_funcall2(path, id_to_path, 1, args);
98
+ rb_check_type(path, RUBY_T_STRING);
99
+ } else {
100
+ path = StringValue(path);
101
+ }
102
+
103
+ return path;
104
+ }
105
+
106
+ static void
107
+ aux_sys_fail(VALUE filesrc, const char *funcname)
108
+ {
109
+ VALUE tmp;
110
+ filesrc = aux_to_path(filesrc);
111
+ if (funcname) {
112
+ tmp = rb_sprintf("%s (%s error)", StringValueCStr(filesrc), funcname);
113
+ } else {
114
+ tmp = rb_sprintf("%s", StringValueCStr(filesrc));
115
+ }
116
+ rb_sys_fail(StringValueCStr(tmp));
117
+ }
118
+
119
+ static size_t
120
+ aux_str_getmem(VALUE obj, const char **pp)
121
+ {
122
+ switch (rb_type(obj)) {
123
+ case RUBY_T_STRING:
124
+ break;
125
+ case RUBY_T_SYMBOL:
126
+ obj = rb_id2str(rb_sym2id(obj));
127
+ break;
128
+ default:
129
+ rb_raise(rb_eTypeError, "expect string or symbol for namespace");
130
+ }
131
+
132
+ size_t len;
133
+ RSTRING_GETMEM(obj, *pp, len);
134
+ return len;
135
+ }
136
+
137
+ static int
138
+ aux_memcasecmp(const char *a, const char *b, size_t n)
139
+ {
140
+ // MEMO: memicmp() があればそちらを使うべき?
141
+
142
+ for (; n > 0; n--, a++, b++) {
143
+ int c = tolower(*(const unsigned char *)a) - tolower(*(const unsigned char *)b);
144
+ if (c) {
145
+ return (c > 0) ? 1 : -1;
146
+ }
147
+ }
148
+
149
+ return 0;
150
+ }
151
+
61
152
 
62
153
  #if defined(HAVE_SYS_EXTATTR_H)
63
- # include "extattr.bsd"
64
- #elif defined(HAVE_ATTR_XATTR_H)
65
- # include "extattr.linux"
154
+ # include "extattr-extattr.h"
66
155
  #elif defined(HAVE_WINNT_H)
67
- # include "extattr.windows"
156
+ # include "extattr-windows.h"
157
+ #elif defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
158
+ # include "extattr-xattr.h"
68
159
  #else
69
- # error ruby extattr not supported on your system
160
+ # error ruby-extattr not supported on your system
70
161
  #endif
71
162
 
72
163
 
73
- static VALUE SYMnamespace;
74
-
75
-
76
- /*
77
- * call-seq:
78
- * file.extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) -> names array
79
- * file.extattr_list(namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
80
- *
81
- * 開いているファイルの拡張属性名一覧を得ます。
82
- *
83
- * ブロックが指定された場合、一つ一つの拡張属性名を渡してブロックが評価されます。ブロックの戻り値は無視されます。
84
- */
85
164
  static VALUE
86
- file_extattr_list(int argc, VALUE argv[], VALUE file)
165
+ aux_should_be_string(VALUE obj)
87
166
  {
88
- VALUE opts = Qnil;
89
- rb_scan_args(argc, argv, "0:", &opts);
90
- return file_extattr_list0(file, file2fd(file),
91
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))));
167
+ rb_check_type(obj, RUBY_T_STRING);
168
+ return obj;
92
169
  }
93
170
 
94
- /*
95
- * call-seq:
96
- * File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) -> names array
97
- * File.extattr_list(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
98
- *
99
- * ファイル名を指定すること以外は File#extattr_list と同じです。
100
- */
101
- static VALUE
102
- file_s_extattr_list(int argc, VALUE argv[], VALUE file)
171
+ static int
172
+ convert_namespace_int(VALUE namespace)
103
173
  {
104
- VALUE path, opts = Qnil;
105
- rb_scan_args(argc, argv, "1:", &path, &opts);
106
- return file_s_extattr_list0(StringValue(path),
107
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))));
174
+ int n = NUM2INT(namespace);
175
+
176
+ if (n == EXTATTR_NAMESPACE_USER ||
177
+ n == EXTATTR_NAMESPACE_SYSTEM) {
178
+
179
+ return n;
180
+ }
181
+
182
+ rb_raise(rb_eArgError,
183
+ "wrong namespace value - #<%s:%p>",
184
+ rb_obj_classname(namespace), (void *)namespace);
108
185
  }
109
186
 
110
- /*
111
- * call-seq:
112
- * File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) -> names array
113
- * File.extattr_list!(path, namespace: File::EXTATTR_NAMESPACE_USER) { |name| ... } -> nil
114
- *
115
- * シンボリックリンクに対する操作という以外は、File.extattr_list と同じです。
116
- */
117
- static VALUE
118
- file_s_extattr_list_link(int argc, VALUE argv[], VALUE file)
187
+ static int
188
+ convert_namespace_str(VALUE namespace)
119
189
  {
120
- VALUE path, opts = Qnil;
121
- rb_scan_args(argc, argv, "1:", &path, &opts);
122
- return file_s_extattr_list_link0(StringValue(path),
123
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))));
190
+ static const char ns_user[] = "user";
191
+ static const int ns_user_len = sizeof(ns_user) / sizeof(ns_user[0]) - 1;
192
+ static const char ns_system[] = "system";
193
+ static const int ns_system_len = sizeof(ns_system) / sizeof(ns_system[0]) - 1;
194
+
195
+ const char *p;
196
+ size_t len = aux_str_getmem(namespace, &p);
197
+
198
+ if (len == ns_user_len && aux_memcasecmp(p, ns_user, ns_user_len) == 0) {
199
+ return EXTATTR_NAMESPACE_USER;
200
+ } else if (len == ns_system_len && aux_memcasecmp(p, ns_system, ns_system_len) == 0) {
201
+ return EXTATTR_NAMESPACE_SYSTEM;
202
+ } else {
203
+ rb_raise(rb_eArgError,
204
+ "wrong namespace - %s (expected to user or system)",
205
+ StringValueCStr(namespace));
206
+ }
124
207
  }
125
208
 
209
+ static int
210
+ conv_namespace(VALUE namespace)
211
+ {
212
+ if (NIL_P(namespace)) {
213
+ return EXTATTR_NAMESPACE_USER;
214
+ } else if (rb_obj_is_kind_of(namespace, rb_cNumeric)) {
215
+ return convert_namespace_int(namespace);
216
+ } else if (rb_obj_is_kind_of(namespace, rb_cString) ||
217
+ rb_obj_is_kind_of(namespace, rb_cSymbol)) {
218
+ return convert_namespace_str(rb_String(namespace));
219
+ } else {
220
+ rb_raise(rb_eArgError,
221
+ "wrong namespace object - %p",
222
+ (void *)namespace);
223
+ }
224
+ }
126
225
 
127
- /*
128
- * call-seq:
129
- * file.extattr_size(name, namespace: File::EXTATTR_NAMESPACE_USER) -> names array
130
- *
131
- * 拡張属性の大きさを取得します。
132
- */
133
- static VALUE
134
- file_extattr_size(int argc, VALUE argv[], VALUE file)
226
+ #if RUBY_API_VERSION_CODE >= 20700
227
+ static void ext_check_file_security(VALUE file, VALUE name, VALUE data) { }
228
+ static void ext_check_path_security(VALUE path, VALUE name, VALUE data) { }
229
+ #else
230
+ static void
231
+ ext_check_file_security(VALUE file, VALUE name, VALUE data)
135
232
  {
136
- VALUE name, opts = Qnil;
137
- rb_scan_args(argc, argv, "1:", &name, &opts);
138
- return file_extattr_size0(file, file2fd(file),
139
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
140
- StringValue(name));
233
+ /*
234
+ * - file が汚染されていない場合、他のオブジェクトも汚染されていてはならない。
235
+ * - file が汚染されている場合、他のオブジェクトの汚染に左右されない。
236
+ * - $SAFE が4以上の場合、非汚染オブジェクトがあれば失敗する。
237
+ *
238
+ * file name data | list get set delete
239
+ * - - - | yes yes yes yes
240
+ * - - T | no
241
+ * - T - | no no no
242
+ * - T T | no
243
+ * T - - | yes yes yes yes
244
+ * T - T | yes
245
+ * T T - | yes yes yes
246
+ * T T T | yes
247
+ */
248
+
249
+ int safe = rb_safe_level();
250
+
251
+ // $SAFE < 1 であれば、常に成功する
252
+ if (safe < 1) {
253
+ return;
254
+ }
255
+
256
+ // 0 < $SAFE < 4 であれば、file が汚染されていれば常に成功、
257
+ // そうでなければ name と data は非汚染状態でなければならない
258
+ if (safe < 4) {
259
+ if (OBJ_TAINTED(file)) {
260
+ return;
261
+ }
262
+ if (OBJ_TAINTED(name) || OBJ_TAINTED(data)) {
263
+ rb_insecure_operation();
264
+ }
265
+ return;
266
+ }
267
+
268
+ // $SAFE は 4以上。すべてのオブジェクトが汚染されていなければならない
269
+ if (!OBJ_TAINTED(file) ||
270
+ (!NIL_P(name) && !OBJ_TAINTED(name)) ||
271
+ (!NIL_P(data) && !OBJ_TAINTED(data))) {
272
+
273
+ rb_insecure_operation();
274
+ }
141
275
  }
142
276
 
143
- /*
144
- * call-seq:
145
- * File.extattr_size(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
146
- */
147
- static VALUE
148
- file_s_extattr_size(int argc, VALUE argv[], VALUE file)
277
+ static void
278
+ ext_check_path_security(VALUE path, VALUE name, VALUE data)
149
279
  {
150
- VALUE path, name, opts = Qnil;
151
- rb_scan_args(argc, argv, "2:", &path, &name, &opts);
152
- return file_s_extattr_size0(StringValue(path),
153
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
154
- StringValue(name));
280
+ /*
281
+ * - すべてのオブジェクトが汚染されていない状態でなければならない。
282
+ * - $SAFE が4以上の場合、常に失敗する。
283
+ *
284
+ * path name data | list get set delete
285
+ * - - - | yes yes yes yes
286
+ * - - T | no
287
+ * - T - | no no no
288
+ * - T T | no
289
+ * T - - | no no no no
290
+ * T - T | no
291
+ * T T - | no no no
292
+ * T T T | no
293
+ */
294
+
295
+ int safe = rb_safe_level();
296
+ if (safe < 1) { return; }
297
+ if (safe < 4) {
298
+ if (OBJ_TAINTED(path) || OBJ_TAINTED(name) || OBJ_TAINTED(data)) {
299
+ rb_insecure_operation();
300
+ }
301
+ } else {
302
+ rb_insecure_operation();
303
+ }
155
304
  }
305
+ #endif
306
+
156
307
 
157
308
  /*
158
309
  * call-seq:
159
- * File.extattr_size!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> size
310
+ * list(path, namespace) -> names array
311
+ * list(path, namespace) { |name| ... } -> nil
160
312
  */
161
313
  static VALUE
162
- file_s_extattr_size_link(int argc, VALUE argv[], VALUE file)
314
+ ext_s_list(VALUE mod, VALUE path, VALUE namespace)
163
315
  {
164
- VALUE path, name, opts = Qnil;
165
- rb_scan_args(argc, argv, "2:", &path, &name, &opts);
166
- return file_s_extattr_size_link0(StringValue(path),
167
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
168
- StringValue(name));
316
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
317
+ ext_check_file_security(path, Qnil, Qnil);
318
+ return file_extattr_list_main(path, file2fd(path),
319
+ conv_namespace(namespace));
320
+ } else {
321
+ ext_check_path_security(path, Qnil, Qnil);
322
+ return file_s_extattr_list_main(aux_to_path(path),
323
+ conv_namespace(namespace));
324
+ }
169
325
  }
170
326
 
171
-
172
327
  /*
173
328
  * call-seq:
174
- * file.extattr_get(name, namespace: File::EXTATTR_NAMESPACE_USER) -> data
329
+ * extattr_list!(path, namespace) -> names array
330
+ * extattr_list!(path, namespace) { |name| ... } -> nil
175
331
  */
176
332
  static VALUE
177
- file_extattr_get(int argc, VALUE argv[], VALUE file)
333
+ ext_s_list_link(VALUE mod, VALUE path, VALUE namespace)
178
334
  {
179
- VALUE name, opts = Qnil;
180
- rb_scan_args(argc, argv, "1:", &name, &opts);
181
- return file_extattr_get0(file, file2fd(file),
182
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
183
- StringValue(name));
335
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
336
+ ext_check_file_security(path, Qnil, Qnil);
337
+ return file_extattr_list_main(path, file2fd(path),
338
+ conv_namespace(namespace));
339
+ } else {
340
+ ext_check_path_security(path, Qnil, Qnil);
341
+ return file_s_extattr_list_link_main(aux_to_path(path),
342
+ conv_namespace(namespace));
343
+ }
184
344
  }
185
345
 
346
+
186
347
  /*
187
348
  * call-seq:
188
- * File.extattr_get(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data
349
+ * size(path, namespace, name) -> size
189
350
  */
190
351
  static VALUE
191
- file_s_extattr_get(int argc, VALUE argv[], VALUE file)
352
+ ext_s_size(VALUE mod, VALUE path, VALUE namespace, VALUE name)
192
353
  {
193
- VALUE path, name, opts = Qnil;
194
- rb_scan_args(argc, argv, "2:", &path, &name, &opts);
195
- return file_s_extattr_get0(StringValue(path),
196
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
197
- StringValue(name));
354
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
355
+ ext_check_file_security(path, name, Qnil);
356
+ return file_extattr_size_main(path, file2fd(path), conv_namespace(namespace),
357
+ aux_should_be_string(name));
358
+ } else {
359
+ ext_check_path_security(path, name, Qnil);
360
+ return file_s_extattr_size_main(aux_to_path(path), conv_namespace(namespace),
361
+ aux_should_be_string(name));
362
+ }
198
363
  }
199
364
 
200
365
  /*
201
366
  * call-seq:
202
- * File.extattr_get!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> data
367
+ * size!(path, namespace, name) -> size
203
368
  */
204
369
  static VALUE
205
- file_s_extattr_get_link(int argc, VALUE argv[], VALUE file)
370
+ ext_s_size_link(VALUE mod, VALUE path, VALUE namespace, VALUE name)
206
371
  {
207
- VALUE path, name, opts = Qnil;
208
- rb_scan_args(argc, argv, "2:", &path, &name, &opts);
209
- return file_s_extattr_get_link0(StringValue(path),
210
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
211
- StringValue(name));
372
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
373
+ ext_check_file_security(path, name, Qnil);
374
+ return file_extattr_size_main(path, file2fd(path), conv_namespace(namespace),
375
+ aux_should_be_string(name));
376
+ } else {
377
+ ext_check_path_security(path, name, Qnil);
378
+ return file_s_extattr_size_link_main(aux_to_path(path), conv_namespace(namespace),
379
+ aux_should_be_string(name));
380
+ }
212
381
  }
213
382
 
214
383
 
215
384
  /*
216
385
  * call-seq:
217
- * file.extattr_set(name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
386
+ * get(path, namespace, name) -> data
218
387
  */
219
388
  static VALUE
220
- file_extattr_set(int argc, VALUE argv[], VALUE file)
389
+ ext_s_get(VALUE mod, VALUE path, VALUE namespace, VALUE name)
221
390
  {
222
- VALUE name, data, opts = Qnil;
223
- rb_scan_args(argc, argv, "11:", &name, &data, &opts);
224
- return file_extattr_set0(file, file2fd(file),
225
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
226
- StringValue(name),
227
- StringValue(data));
391
+ VALUE v;
392
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
393
+ ext_check_file_security(path, name, Qnil);
394
+ v = file_extattr_get_main(path, file2fd(path), conv_namespace(namespace),
395
+ aux_should_be_string(name));
396
+ } else {
397
+ ext_check_path_security(path, name, Qnil);
398
+ v = file_s_extattr_get_main(aux_to_path(path), conv_namespace(namespace),
399
+ aux_should_be_string(name));
400
+ }
401
+
402
+ rb_obj_infect(v, path);
403
+ return v;
228
404
  }
229
405
 
230
406
  /*
231
407
  * call-seq:
232
- * File.extattr_set(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
408
+ * get!(path, namespace, name) -> data
233
409
  */
234
410
  static VALUE
235
- file_s_extattr_set(int argc, VALUE argv[], VALUE file)
411
+ ext_s_get_link(VALUE mod, VALUE path, VALUE namespace, VALUE name)
236
412
  {
237
- VALUE path, name, data, opts = Qnil;
238
- rb_scan_args(argc, argv, "21:", &path, &name, &data, &opts);
239
- return file_s_extattr_set0(StringValue(path),
240
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
241
- StringValue(name),
242
- StringValue(data));
413
+ VALUE v;
414
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
415
+ ext_check_file_security(path, name, Qnil);
416
+ v = file_extattr_get_main(path, file2fd(path), conv_namespace(namespace),
417
+ aux_should_be_string(name));
418
+ } else {
419
+ ext_check_path_security(path, name, Qnil);
420
+ v = file_s_extattr_get_link_main(aux_to_path(path), conv_namespace(namespace),
421
+ aux_should_be_string(name));
422
+ }
423
+
424
+ rb_obj_infect(v, path);
425
+ return v;
243
426
  }
244
427
 
428
+
245
429
  /*
246
430
  * call-seq:
247
- * File.extattr_set!(path, name, data, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
431
+ * set(path, namespace, name, data) -> nil
248
432
  */
249
433
  static VALUE
250
- file_s_extattr_set_link(int argc, VALUE argv[], VALUE file)
434
+ ext_s_set(VALUE mod, VALUE path, VALUE namespace, VALUE name, VALUE data)
251
435
  {
252
- VALUE path, name, data, opts = Qnil;
253
- rb_scan_args(argc, argv, "21:", &path, &name, &data, &opts);
254
- return file_s_extattr_set_link0(StringValue(path),
255
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
256
- StringValue(name),
257
- StringValue(data));
436
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
437
+ ext_check_file_security(path, name, Qnil);
438
+ return file_extattr_set_main(path, file2fd(path),
439
+ conv_namespace(namespace),
440
+ aux_should_be_string(name), aux_should_be_string(data));
441
+ } else {
442
+ ext_check_path_security(path, name, Qnil);
443
+ return file_s_extattr_set_main(aux_to_path(path),
444
+ conv_namespace(namespace),
445
+ aux_should_be_string(name), aux_should_be_string(data));
446
+ }
258
447
  }
259
448
 
260
-
261
449
  /*
262
450
  * call-seq:
263
- * file.extattr_delete(name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
451
+ * set!(path, namespace, name, data) -> nil
264
452
  */
265
453
  static VALUE
266
- file_extattr_delete(int argc, VALUE argv[], VALUE file)
454
+ ext_s_set_link(VALUE mod, VALUE path, VALUE namespace, VALUE name, VALUE data)
267
455
  {
268
- VALUE name, opts = Qnil;
269
- rb_scan_args(argc, argv, "1:", &name, &opts);
270
- return file_extattr_delete0(file, file2fd(file),
271
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
272
- StringValue(name));
456
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
457
+ ext_check_file_security(path, name, Qnil);
458
+ return file_extattr_set_main(path, file2fd(path),
459
+ conv_namespace(namespace),
460
+ aux_should_be_string(name), aux_should_be_string(data));
461
+ } else {
462
+ ext_check_path_security(path, name, Qnil);
463
+ return file_s_extattr_set_link_main(aux_to_path(path),
464
+ conv_namespace(namespace),
465
+ aux_should_be_string(name), aux_should_be_string(data));
466
+ }
273
467
  }
274
468
 
469
+
275
470
  /*
276
471
  * call-seq:
277
- * File.extattr_delete(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
472
+ * delete(path, namespace, name) -> nil
278
473
  */
279
474
  static VALUE
280
- file_s_extattr_delete(int argc, VALUE argv[], VALUE file)
475
+ ext_s_delete(VALUE mod, VALUE path, VALUE namespace, VALUE name)
281
476
  {
282
- VALUE path, name, opts = Qnil;
283
- rb_scan_args(argc, argv, "2:", &path, &name, &opts);
284
- return file_s_extattr_delete0(StringValue(path),
285
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
286
- StringValue(name));
477
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
478
+ ext_check_file_security(path, name, Qnil);
479
+ return file_extattr_delete_main(path, file2fd(path), conv_namespace(namespace),
480
+ aux_should_be_string(name));
481
+ } else {
482
+ ext_check_path_security(path, name, Qnil);
483
+ return file_s_extattr_delete_main(aux_to_path(path), conv_namespace(namespace),
484
+ aux_should_be_string(name));
485
+ }
287
486
  }
288
487
 
289
488
  /*
290
489
  * call-seq:
291
- * File.extattr_delete!(path, name, namespace: File::EXTATTR_NAMESPACE_USER) -> nil
490
+ * delete!(path, namespace, name) -> nil
292
491
  */
293
492
  static VALUE
294
- file_s_extattr_delete_link(int argc, VALUE argv[], VALUE file)
493
+ ext_s_delete_link(VALUE mod, VALUE path, VALUE namespace, VALUE name)
295
494
  {
296
- VALUE path, name, opts = Qnil;
297
- rb_scan_args(argc, argv, "2:", &path, &name, &opts);
298
- return file_s_extattr_delete_link0(StringValue(path),
299
- NUM2INT(hash_lookup(opts, SYMnamespace, INT2NUM(EXTATTR_NAMESPACE_USER))),
300
- StringValue(name));
495
+ if (rb_obj_is_kind_of(path, rb_cFile)) {
496
+ ext_check_file_security(path, name, Qnil);
497
+ return file_extattr_delete_main(path, file2fd(path), conv_namespace(namespace),
498
+ aux_should_be_string(name));
499
+ } else {
500
+ ext_check_path_security(path, name, Qnil);
501
+ return file_s_extattr_delete_link_main(aux_to_path(path), conv_namespace(namespace),
502
+ aux_should_be_string(name));
503
+ }
301
504
  }
302
505
 
303
506
 
304
- /*
305
- * Document-class: File
306
- *
307
- * File クラスに拡張属性を操作するメソッドを追加します。
308
- *
309
- * 感嘆符(『!』)のついたメソッドは、シンボリックリンクに対する操作となります。
310
- *
311
- * メソッドにキーワード引数として <code>namespace:</code> を与えることにより、拡張属性の名前空間を指定することが出来ます。
312
- * 現在の実装においては <code>EXTATTR_NAMESPACE_USER</code> と <code>EXTATTR_NAMESPACE_SYSTEM</code> のみが利用可能です。
313
- */
314
-
315
-
316
507
  void
317
508
  Init_extattr(void)
318
509
  {
319
- SYMnamespace = ID2SYM(rb_intern("namespace"));
320
-
321
- rb_const_set(rb_cFile, rb_intern("EXTATTR_NAMESPACE_USER"), INT2NUM(EXTATTR_NAMESPACE_USER));
322
- rb_const_set(rb_cFile, rb_intern("EXTATTR_NAMESPACE_SYSTEM"), INT2NUM(EXTATTR_NAMESPACE_SYSTEM));
323
-
324
- rb_define_method(rb_cFile, "extattr_list", RUBY_METHOD_FUNC(file_extattr_list), -1);
325
- rb_define_singleton_method(rb_cFile, "extattr_list", RUBY_METHOD_FUNC(file_s_extattr_list), -1);
326
- rb_define_singleton_method(rb_cFile, "extattr_list!", RUBY_METHOD_FUNC(file_s_extattr_list_link), -1);
327
-
328
- rb_define_method(rb_cFile, "extattr_size", RUBY_METHOD_FUNC(file_extattr_size), -1);
329
- rb_define_singleton_method(rb_cFile, "extattr_size", RUBY_METHOD_FUNC(file_s_extattr_size), -1);
330
- rb_define_singleton_method(rb_cFile, "extattr_size!", RUBY_METHOD_FUNC(file_s_extattr_size_link), -1);
331
-
332
- rb_define_method(rb_cFile, "extattr_get", RUBY_METHOD_FUNC(file_extattr_get), -1);
333
- rb_define_singleton_method(rb_cFile, "extattr_get", RUBY_METHOD_FUNC(file_s_extattr_get), -1);
334
- rb_define_singleton_method(rb_cFile, "extattr_get!", RUBY_METHOD_FUNC(file_s_extattr_get_link), -1);
335
-
336
- rb_define_method(rb_cFile, "extattr_set", RUBY_METHOD_FUNC(file_extattr_set), -1);
337
- rb_define_singleton_method(rb_cFile, "extattr_set", RUBY_METHOD_FUNC(file_s_extattr_set), -1);
338
- rb_define_singleton_method(rb_cFile, "extattr_set!", RUBY_METHOD_FUNC(file_s_extattr_set_link), -1);
339
-
340
- rb_define_method(rb_cFile, "extattr_delete", RUBY_METHOD_FUNC(file_extattr_delete), -1);
341
- rb_define_singleton_method(rb_cFile, "extattr_delete", RUBY_METHOD_FUNC(file_s_extattr_delete), -1);
342
- rb_define_singleton_method(rb_cFile, "extattr_delete!", RUBY_METHOD_FUNC(file_s_extattr_delete_link), -1);
343
-
344
- setup();
510
+ #if HAVE_RB_EXT_RACTOR_SAFE
511
+ rb_ext_ractor_safe(true);
512
+ #endif
513
+ id_downcase = rb_intern("downcase");
514
+ id_to_path = rb_intern("to_path");
515
+
516
+ mExtAttr = rb_define_module("ExtAttr");
517
+ rb_define_const(mExtAttr, "USER", ID2SYM(rb_intern("user")));
518
+ rb_define_const(mExtAttr, "SYSTEM", ID2SYM(rb_intern("system")));
519
+
520
+ rb_define_singleton_method(mExtAttr, "list", RUBY_METHOD_FUNC(ext_s_list), 2);
521
+ rb_define_singleton_method(mExtAttr, "list!", RUBY_METHOD_FUNC(ext_s_list_link), 2);
522
+ rb_define_singleton_method(mExtAttr, "size", RUBY_METHOD_FUNC(ext_s_size), 3);
523
+ rb_define_singleton_method(mExtAttr, "size!", RUBY_METHOD_FUNC(ext_s_size_link), 3);
524
+ rb_define_singleton_method(mExtAttr, "get", RUBY_METHOD_FUNC(ext_s_get), 3);
525
+ rb_define_singleton_method(mExtAttr, "get!", RUBY_METHOD_FUNC(ext_s_get_link), 3);
526
+ rb_define_singleton_method(mExtAttr, "set", RUBY_METHOD_FUNC(ext_s_set), 4);
527
+ rb_define_singleton_method(mExtAttr, "set!", RUBY_METHOD_FUNC(ext_s_set_link), 4);
528
+ rb_define_singleton_method(mExtAttr, "delete", RUBY_METHOD_FUNC(ext_s_delete), 3);
529
+ rb_define_singleton_method(mExtAttr, "delete!", RUBY_METHOD_FUNC(ext_s_delete_link), 3);
530
+
531
+ extattr_init_implement();
345
532
  }