solaris-file 0.3.1

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/CHANGES ADDED
@@ -0,0 +1,19 @@
1
+ == 0.3.1 - 11-Jul-2006
2
+ * Fixed a potential 64 bit bug in a struct declaration.
3
+ * Minor RDoc updates, changes and internal cosmetic changes.
4
+
5
+ == 0.3.0 - 13-Jun-2005
6
+ * Added the File.resolvepath and File.realpath methods.
7
+ * Code cleanup. Attempting to pass a path greater than PATH_MAX
8
+ now raises an ArgumentError.
9
+ * More tests added.
10
+
11
+ == 0.2.0 - 1-Apr-2005
12
+ * The Solaris::FileError class has been changed to File::SolarisError.
13
+ * Added internal taint checking for methods that accept String arguments.
14
+ * Improved error handling and general cleanup.
15
+ * Added README and CHANGES files. The former replaces the doc/file.txt file.
16
+ * Added a gemspec.
17
+
18
+ == 0.1.0 - 27-Jan-2005
19
+ * Initial release.
data/MANIFEST ADDED
@@ -0,0 +1,14 @@
1
+ extconf.rb
2
+ MANIFEST
3
+ README
4
+ CHANGES
5
+ solaris-file.gemspec
6
+
7
+ examples/bar.txt
8
+ examples/foo.txt
9
+ examples/test.rb
10
+
11
+ lib/solaris/sfile.c
12
+ lib/solaris/sfile.h
13
+
14
+ test/tc_solaris_file.rb
data/README ADDED
@@ -0,0 +1,112 @@
1
+ == Description
2
+ Adds ACL support for the File class on Solaris.
3
+
4
+ == Prerequisites
5
+ Ruby 1.8.x
6
+
7
+ == Installation
8
+ ruby extconf.rb
9
+ make
10
+ ruby test/tc_solaris_file.rb
11
+ make site-install
12
+
13
+ == Synopsis
14
+ require "solaris/file"
15
+
16
+ f = "some_file.txt"
17
+ acl_text = "user::rw-,user:nobody:r--,"
18
+ acl_text << "group::r--,group:sys:r--,mask:r--,other:r--"
19
+
20
+ File.trivial?(f) # probably true
21
+ File.acl_write_text(acl_text)
22
+
23
+ # No longer a trivial file
24
+ File.trivial?(f) # false
25
+ File.acl_read(f).each{ |acl| p acl }
26
+
27
+ == Class Methods
28
+ File.acl_count(file_name)
29
+ Returns the number of ACL entries for the file. Returns 0 if it's a
30
+ trivial file.
31
+
32
+ File.acl_read(file_name)
33
+ Returns an Array of ACLStruct's or nil if file_name is a trivial file.
34
+
35
+ Fiel.acl_read_text(file_name)
36
+ Returns a String form of the ACL entries for the file. Returns nil if
37
+ it's a trivial ACL.
38
+
39
+ File.acl_write_text(file_name, acl_string)
40
+ Accepts a formatted ACL string that set the ACL for the file. If the
41
+ string is badly formed, a File::SolarisError is raised.
42
+
43
+ File.realpath(path)
44
+ Resolves all symbolic links in +path+. Resolves to an absolute pathname
45
+ where possible.
46
+
47
+ File.resolvepath(path)
48
+ Resolves all symbolic links in +path+. All "." components are removed, as
49
+ well as all nonleading ".." components and their preceding directory
50
+ component. If leading ".." components resolve to the root directory, they
51
+ are replaced by "/".
52
+
53
+ File.trivial?(file_name)
54
+ Returns true if the file is a trivial ACL file, i.e. has no ACL entries for
55
+ additional users or groups.
56
+
57
+ = Instance Methods
58
+ File#acl_count
59
+ Returns the number of ACL entries for the file. Returns 0 if it's a
60
+ trivial file.
61
+
62
+ File#acl_read
63
+ Returns an Array of ACLStruct's.
64
+
65
+ File#acl_read_text
66
+ Returns a String form of the ACL entries for the file. Returns nil if
67
+ it's a trivial ACL.
68
+
69
+ File#acl_write_text(acl_string)
70
+ Accepts a formatted ACL string that set the ACL for the file. If the
71
+ string is badly formed, a File::SolarisError is raised.
72
+
73
+ File#trivial?
74
+ Returns true if the file is a trivial ACL file, i.e. has no ACL entries for
75
+ additional users or groups
76
+
77
+ == Constants
78
+ File::SOLARIS_VERSION
79
+ Returns the current version number of this package as a String.
80
+
81
+ == Error Classes
82
+ File::SolarisError < StandardError
83
+ Raised if anything goes wrong with any of the above methods.
84
+
85
+ == Known Bugs
86
+ None that I am aware of. Please report any bugs using the tracker on the
87
+ project page at http://www.rubyforge.org/projects/solarisutils
88
+
89
+ == Future Plans
90
+ Add File.acl_write and File#acl_write methods that accept an array of
91
+ ACLStruct's.
92
+ Add support for extended file attributes.
93
+
94
+ == Developer's Notes
95
+ This is a BETA release. I have not totally settled on the API.
96
+
97
+ == Copyright
98
+ (C) 2005, 2006 Daniel J. Berger
99
+ All Rights Reserved
100
+
101
+ == Warranty
102
+ This package is provided "as is" and without any express or
103
+ implied warranties, including, without limitation, the implied
104
+ warranties of merchantability and fitness for a particular purpose.
105
+
106
+ == License
107
+ Ruby's
108
+
109
+ == Author
110
+ Daniel J. Berger
111
+ djberg96 [at gmail dot com]
112
+ imperator on IRC (irc.freenode.net)
data/examples/test.rb ADDED
@@ -0,0 +1,60 @@
1
+ #############################################################
2
+ # test.rb
3
+ #
4
+ # Test script for general futzing. Modify as you see fit.
5
+ #############################################################
6
+ base = File.basename(Dir.pwd)
7
+
8
+ if base == "examples" || base =~ /solaris-file.*/
9
+ require "ftools"
10
+ Dir.chdir("..") if base == "examples"
11
+ Dir.mkdir("solaris") unless File.exists?("solaris")
12
+ File.copy("file.so","solaris")
13
+ $LOAD_PATH.unshift(Dir.pwd)
14
+ Dir.chdir("examples")
15
+ end
16
+
17
+ require "solaris/file"
18
+ require "pp"
19
+
20
+ puts
21
+ puts "Version: " + File::SOLARIS_VERSION
22
+ puts "-" * 20
23
+
24
+ file1 = "foo.txt"
25
+ file2 = "bar.txt"
26
+
27
+ File.open(file1,"w+"){ |fh| fh.puts "foo" }
28
+ File.open(file2,"w+"){ |fh| fh.puts "bar" }
29
+
30
+ acl_text = "user::rw-,user:nobody:r--,group::r--,group:sys:r--,mask:r--,other:r--"
31
+ acl_text2 = "user::rw-,user:nobody:r--,group::r--,group:sys:r--,mask:r--,other:rw-"
32
+
33
+ pp File.acl_count(file1) # Should be 0
34
+ pp File.acl_read(file1) # Should return nil
35
+ pp File.acl_read_text(file1) # Should return nil
36
+ pp File.trivial?(file1) # Should return true
37
+
38
+ File.acl_write_text(file1,acl_text)
39
+
40
+ pp File.acl_count(file1) # Should now be 6
41
+ pp File.acl_read(file1) # Should return 6 ACL Struct's
42
+ pp File.acl_read_text(file1) # Should return an string like 'acl_text' above
43
+ pp File.trivial?(file1) # Should return false
44
+
45
+ pp File.acl_count(file2)
46
+ pp File.acl_read(file2)
47
+ pp File.acl_read_text(file2)
48
+ pp File.trivial?(file2)
49
+
50
+ # Use instance methods instead this time
51
+ File.open(file2){ |fh|
52
+ fh.acl_write_text(acl_text2)
53
+ pp fh.acl_count
54
+ pp fh.acl_read
55
+ pp fh.acl_read_text
56
+ pp fh.trivial?
57
+ }
58
+
59
+ File.delete(file1) if File.exists?(file1)
60
+ File.delete(file2) if File.exists?(file2)
data/extconf.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "mkmf"
2
+ require "ftools"
3
+
4
+ File.copy("lib/solaris/sfile.c",".")
5
+ File.copy("lib/solaris/sfile.h",".")
6
+
7
+ have_library("sec")
8
+ create_makefile("solaris/file")
@@ -0,0 +1,423 @@
1
+ #include "ruby.h"
2
+ #include "rubyio.h"
3
+ #include <sys/acl.h>
4
+ #include <sys/param.h>
5
+ #include <unistd.h>
6
+ #include "sfile.h"
7
+
8
+ /*
9
+ * call-seq:
10
+ * File.acl_count(file_name)
11
+ *
12
+ * Returns the number of ACL entries for +file_name+. Returns 0 if +file_name+
13
+ * is a trivial file.
14
+ */
15
+ static VALUE acl_count(VALUE klass, VALUE v_path){
16
+ int num_acls = 0;
17
+ char pathp[PATH_MAX];
18
+
19
+ SafeStringValue(v_path);
20
+
21
+ if(strlcpy(pathp, StringValuePtr(v_path), PATH_MAX) >= PATH_MAX)
22
+ rb_raise(rb_eArgError, "path length exceeds limit of: %i", PATH_MAX);
23
+
24
+ if((num_acls = acl(pathp, GETACLCNT, 0, NULL)) == -1)
25
+ rb_sys_fail(0);
26
+
27
+ if(num_acls == MIN_ACL_ENTRIES)
28
+ num_acls = 0;
29
+
30
+ return INT2FIX(num_acls);
31
+ }
32
+
33
+ /*
34
+ * call-seq:
35
+ * File#acl_count
36
+ *
37
+ * Returns the number of ACL entries for the current handle. Returns 0 if
38
+ * the file is a trivial file.
39
+ */
40
+ static VALUE acl_icount(VALUE self){
41
+ int num_acls = 0;
42
+ int fildes = FIX2INT(rb_funcall(self,rb_intern("fileno"), 0, 0));
43
+
44
+ if((num_acls = facl(fildes, GETACLCNT, 0, NULL)) == -1)
45
+ rb_sys_fail(0);
46
+
47
+ if(num_acls == MIN_ACL_ENTRIES)
48
+ num_acls = 0;
49
+
50
+ return INT2FIX(num_acls);
51
+ }
52
+
53
+ /*
54
+ * call-seq:
55
+ * File.acl_read(file_name)
56
+ *
57
+ * Returns an array of ACLStruct's that contain three members each:
58
+ *
59
+ * - acl_type (String)
60
+ * - acl_id (Integer)
61
+ * - acl_perm (Integer)
62
+ *
63
+ * Returns nil if +file_name+ is a trivial file.
64
+ */
65
+ static VALUE acl_read(VALUE klass, VALUE v_path){
66
+ int num_acls = 0;
67
+ char pathp[PATH_MAX];
68
+ VALUE v_array = Qnil;
69
+ int i;
70
+
71
+ SafeStringValue(v_path);
72
+
73
+ if(strlcpy(pathp, StringValuePtr(v_path), PATH_MAX) >= PATH_MAX)
74
+ rb_raise(rb_eArgError, "path length exceeds limit of: %i", PATH_MAX);
75
+
76
+ if((num_acls = acl(pathp, GETACLCNT, 0, NULL)) == -1)
77
+ rb_sys_fail(0);
78
+
79
+ if(num_acls != MIN_ACL_ENTRIES){
80
+ aclent_t* acl_buf;
81
+ v_array = rb_ary_new();
82
+
83
+ if( (acl_buf = malloc(sizeof(aclent_t) * num_acls) ) == NULL)
84
+ rb_sys_fail(0);
85
+
86
+ if(acl(pathp, GETACL, num_acls, acl_buf) != num_acls)
87
+ rb_sys_fail(0);
88
+
89
+ for(i = 0; i < num_acls; i++){
90
+ rb_ary_push(v_array,
91
+ rb_struct_new(sACLStruct,
92
+ acl_type_string(acl_buf[i].a_type),
93
+ INT2FIX(acl_buf[i].a_id),
94
+ INT2FIX(acl_buf[i].a_perm)
95
+ )
96
+ );
97
+ }
98
+
99
+ free(acl_buf);
100
+ }
101
+
102
+ return v_array;
103
+ }
104
+
105
+ /*
106
+ * call-seq:
107
+ * File#acl_read
108
+ *
109
+ * Returns an array of ACLStruct's that contain three members each:
110
+ *
111
+ * - acl_type (String)
112
+ * - acl_id (Integer)
113
+ * - acl_perm (Integer)
114
+ *
115
+ * Returns nil if the file is a trivial file.
116
+ */
117
+ static VALUE acl_iread(VALUE self){
118
+ int num_acls = 0;
119
+ int fildes = FIX2INT(rb_funcall(self,rb_intern("fileno"),0,0));
120
+ VALUE v_array = Qnil;
121
+ int i;
122
+
123
+ if( (num_acls = facl(fildes, GETACLCNT, 0, NULL)) == -1)
124
+ rb_sys_fail(0);
125
+
126
+ if(num_acls != MIN_ACL_ENTRIES){
127
+ aclent_t* acl_buf;
128
+ v_array = rb_ary_new();
129
+
130
+ if( (acl_buf = malloc(sizeof(aclent_t) * num_acls) ) == NULL)
131
+ rb_sys_fail(0);
132
+
133
+ if(facl(fildes, GETACL, num_acls, acl_buf) != num_acls)
134
+ rb_sys_fail(0);
135
+
136
+ for(i = 0; i < num_acls; i++){
137
+ rb_ary_push(v_array,
138
+ rb_struct_new(sACLStruct,
139
+ acl_type_string(acl_buf[i].a_type),
140
+ INT2FIX(acl_buf[i].a_id),
141
+ INT2FIX(acl_buf[i].a_perm)
142
+ )
143
+ );
144
+ }
145
+
146
+ free(acl_buf);
147
+ }
148
+ return v_array;
149
+ }
150
+
151
+ /*
152
+ * call-seq:
153
+ * File.acl_read_text(file_name)
154
+ *
155
+ * Returns a textual representation of the ACL for +file_name+. If +file_name+
156
+ * is a trivial file, nil is returned.
157
+ */
158
+ static VALUE acl_read_text(VALUE klass, VALUE v_path){
159
+ aclent_t* acl_buf;
160
+ int num_acls = 0;
161
+ char* acl_text;
162
+ char pathp[PATH_MAX];
163
+ VALUE v_text = Qnil;
164
+
165
+ SafeStringValue(v_path);
166
+
167
+ if(strlcpy(pathp, StringValuePtr(v_path), PATH_MAX) >= PATH_MAX)
168
+ rb_raise(rb_eArgError, "path length exceeds limit of: %i", PATH_MAX);
169
+
170
+ if( (num_acls = acl(pathp, GETACLCNT, 0, NULL)) == -1)
171
+ rb_sys_fail(0);
172
+
173
+ if(num_acls != MIN_ACL_ENTRIES){
174
+ if( (acl_buf = malloc(sizeof(aclent_t) * num_acls) ) == NULL)
175
+ rb_sys_fail(0);
176
+
177
+ if(acl(pathp, GETACL, num_acls, acl_buf) != num_acls)
178
+ rb_sys_fail(0);
179
+
180
+ acl_text = acltotext(acl_buf, num_acls);
181
+
182
+ free(acl_buf);
183
+ v_text = rb_str_new2(acl_text);
184
+ }
185
+
186
+ return v_text;
187
+ }
188
+
189
+ /*
190
+ * call-seq:
191
+ * File.acl_write_text(file_name, acl_text)
192
+ *
193
+ * Sets the ACL for +file_name+ using +acl_text+. The +acl_text+ argument is a
194
+ * human readable ACL text String.
195
+ *
196
+ * If +acl_text+ is invalid then a Solaris::FileError is raised, and in most
197
+ * cases the offending entry number will be identified.
198
+ */
199
+ static VALUE acl_write_text(VALUE klass, VALUE v_path, VALUE v_text){
200
+ aclent_t* acl_buf;
201
+ int num_acls, which;
202
+ char pathp[PATH_MAX];
203
+ char* acl_text = StringValuePtr(v_text);
204
+ int rv;
205
+
206
+ SafeStringValue(v_path);
207
+ SafeStringValue(v_text);
208
+
209
+ if(strlcpy(pathp, StringValuePtr(v_path), PATH_MAX) >= PATH_MAX)
210
+ rb_raise(rb_eArgError, "path length exceeds limit of: %i", PATH_MAX);
211
+
212
+ if((acl_buf = aclfromtext(acl_text, &num_acls)) == NULL)
213
+ rb_raise(cSolarisFileError, "invalid ACL text");
214
+
215
+ rv = aclcheck(acl_buf, num_acls, &which);
216
+ do_acl_check(rv, which);
217
+
218
+ if(acl(pathp, SETACL, num_acls, acl_buf) == -1){
219
+ free(acl_text);
220
+ rb_sys_fail(0);
221
+ }
222
+
223
+ free(acl_text);
224
+ free(acl_buf);
225
+
226
+ return klass;
227
+ }
228
+
229
+ /*
230
+ * call-seq:
231
+ * File.resolvepath(path)
232
+ *
233
+ * Resolves all symbolic links in +path+. All "." components are removed, as
234
+ * well as all nonleading ".." components and their preceding directory
235
+ * component. If leading ".." components resolve to the root directory, they
236
+ * are replaced by "/".
237
+ */
238
+ static VALUE solaris_resolvepath(VALUE klass, VALUE v_path){
239
+ char pathp[PATH_MAX];
240
+
241
+ SafeStringValue(v_path);
242
+ memset(pathp, 0, PATH_MAX);
243
+
244
+ if(resolvepath(StringValuePtr(v_path), pathp, PATH_MAX) == -1)
245
+ rb_sys_fail(0);
246
+
247
+ return rb_str_new2(pathp);
248
+ }
249
+
250
+ /*
251
+ * call-seq:
252
+ * File.realpath(path)
253
+ *
254
+ * Resolves all symbolic links in +path+. Resolves to an absolute pathname
255
+ * where possible.
256
+ *
257
+ * The difference between this method and File.resolvepath is that this method
258
+ * will resolve to an absolute pathname where possible.
259
+ */
260
+ static VALUE solaris_realpath(VALUE klass, VALUE v_path){
261
+ char pathp[PATH_MAX];
262
+
263
+ SafeStringValue(v_path);
264
+
265
+ if(realpath(StringValuePtr(v_path), pathp) == NULL)
266
+ rb_sys_fail(0);
267
+
268
+ return rb_str_new2(pathp);
269
+ }
270
+
271
+ /* Instance Methods */
272
+
273
+ /*
274
+ * call-seq:
275
+ * File#acl_write_text(acl_text)
276
+ *
277
+ * Sets the ACL for the file using +acl_text+. The +acl_text+ argument is a
278
+ * human readable ACL text String.
279
+ *
280
+ * If +acl_text+ is invalid then a File::SolarisError is raised, and in most
281
+ * cases the offending entry number will be identified.
282
+ */
283
+ static VALUE acl_iwrite_text(VALUE self, VALUE v_text){
284
+ aclent_t* acl_buf;
285
+ int num_acls, which;
286
+ char* acl_text = StringValuePtr(v_text);
287
+ int fildes = FIX2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
288
+ int rv;
289
+
290
+ SafeStringValue(v_text);
291
+
292
+ if((acl_buf = aclfromtext(acl_text, &num_acls)) == NULL)
293
+ rb_raise(cSolarisFileError, "invalid ACL text");
294
+
295
+ rv = aclcheck(acl_buf, num_acls, &which);
296
+ do_acl_check(rv, which);
297
+
298
+ if(facl(fildes, SETACL, num_acls, acl_buf) == -1){
299
+ free(acl_text);
300
+ rb_sys_fail(0);
301
+ }
302
+
303
+ free(acl_text);
304
+ free(acl_buf);
305
+
306
+ return self;
307
+ }
308
+
309
+
310
+ /*
311
+ * call-seq:
312
+ * File#acl_read_text
313
+ *
314
+ * Returns a textual representation of the ACL for the current handle. If
315
+ * the file is a trivial file, nil is returned.
316
+ */
317
+ static VALUE acl_iread_text(VALUE self){
318
+ char* acl_text;
319
+ int num_acls = 0;
320
+ int fildes = FIX2INT(rb_funcall(self,rb_intern("fileno"),0,0));
321
+ VALUE v_text = Qnil;
322
+
323
+ if( (num_acls = facl(fildes,GETACLCNT,0,NULL)) == -1)
324
+ rb_sys_fail(0);
325
+
326
+ if(num_acls != MIN_ACL_ENTRIES){
327
+ aclent_t* acl_buf;
328
+
329
+ if( (acl_buf = malloc(sizeof(aclent_t) * num_acls) ) == NULL)
330
+ rb_sys_fail(0);
331
+
332
+ if(facl(fildes, GETACL, num_acls, acl_buf) != num_acls)
333
+ rb_sys_fail(0);
334
+
335
+ acl_text = acltotext(acl_buf,num_acls);
336
+
337
+ free(acl_buf);
338
+ v_text = rb_str_new2(acl_text);
339
+ }
340
+
341
+ return v_text;
342
+ }
343
+
344
+ /*
345
+ * call-seq:
346
+ * File.trivial?(file_name)
347
+ *
348
+ * Returns true if +file_name+ is a trivial file, i.e. has no additional ACL
349
+ * entries. Otherwise, it returns false.
350
+ */
351
+ static VALUE acl_trivial(VALUE klass, VALUE v_path){
352
+ char pathp[PATH_MAX];
353
+ int num_acls = 0;
354
+ VALUE v_bool = Qfalse;
355
+
356
+ SafeStringValue(v_path);
357
+
358
+ if(strlcpy(pathp, StringValuePtr(v_path), PATH_MAX) >= PATH_MAX)
359
+ rb_raise(rb_eArgError, "path length exceeds limit of: %i", PATH_MAX);
360
+
361
+ if((num_acls = acl(pathp, GETACLCNT, 0, NULL)) == -1)
362
+ rb_sys_fail(0);
363
+
364
+ if(num_acls == MIN_ACL_ENTRIES)
365
+ v_bool = Qtrue;
366
+
367
+ return v_bool;
368
+ }
369
+
370
+ /*
371
+ * call-seq:
372
+ * File#trivial?
373
+ *
374
+ * Returns true if the current file is a trivial file, i.e. has no additional
375
+ * ACL entries. Otherwise, it returns false.
376
+ */
377
+ static VALUE acl_itrivial(VALUE self){
378
+ int fildes = FIX2INT(rb_funcall(self,rb_intern("fileno"),0,0));
379
+ int num_acls = 0;
380
+ VALUE v_bool = Qfalse;
381
+
382
+ if( (num_acls = facl(fildes,GETACLCNT,0,NULL)) == -1)
383
+ rb_sys_fail(0);
384
+
385
+ if(num_acls == MIN_ACL_ENTRIES)
386
+ v_bool = Qtrue;
387
+
388
+ return v_bool;
389
+ }
390
+
391
+ /*
392
+ * Adds ACL support for the File class on Solaris
393
+ */
394
+ void Init_file(){
395
+ /* Error Classes */
396
+ cSolarisFileError = rb_define_class_under(rb_cFile, "SolarisError",
397
+ rb_eStandardError
398
+ );
399
+
400
+ /* Class Methods */
401
+ rb_define_singleton_method(rb_cFile, "acl_count", acl_count, 1);
402
+ rb_define_singleton_method(rb_cFile, "acl_read", acl_read, 1);
403
+ rb_define_singleton_method(rb_cFile, "acl_read_text", acl_read_text, 1);
404
+ rb_define_singleton_method(rb_cFile, "acl_write_text", acl_write_text, 2);
405
+ rb_define_singleton_method(rb_cFile, "trivial?", acl_trivial, 1);
406
+ rb_define_singleton_method(rb_cFile, "realpath", solaris_realpath, 1);
407
+ rb_define_singleton_method(rb_cFile, "resolvepath", solaris_resolvepath, 1);
408
+
409
+ /* Instance Methods */
410
+ rb_define_method(rb_cFile,"acl_count", acl_icount, 0);
411
+ rb_define_method(rb_cFile,"acl_read", acl_iread, 0);
412
+ rb_define_method(rb_cFile,"acl_read_text", acl_iread_text, 0);
413
+ rb_define_method(rb_cFile,"acl_write_text", acl_iwrite_text, 1);
414
+ rb_define_method(rb_cFile,"trivial?", acl_itrivial, 0);
415
+
416
+ /* Structs */
417
+ sACLStruct = rb_struct_define("ACLStruct",
418
+ "acl_type", "acl_id", "acl_perm", NULL
419
+ );
420
+
421
+ /* Constants */
422
+ rb_define_const(rb_cFile, "SOLARIS_VERSION", rb_str_new2(SOLARIS_VERSION));
423
+ }
@@ -0,0 +1,78 @@
1
+ #define SOLARIS_VERSION "0.3.1"
2
+ #define MAX_STRING 512
3
+
4
+ VALUE cSolarisFileError;
5
+ VALUE sACLStruct;
6
+
7
+ /*
8
+ * Converts a numeric ACL type into a human readable string.
9
+ */
10
+ static VALUE acl_type_string(int acl_type){
11
+ VALUE rbACLType;
12
+
13
+ switch(acl_type){
14
+ case USER: case USER_OBJ:
15
+ rbACLType = rb_str_new2("user");
16
+ break;
17
+ case GROUP: case GROUP_OBJ:
18
+ rbACLType = rb_str_new2("group");
19
+ break;
20
+ case OTHER_OBJ:
21
+ rbACLType = rb_str_new2("other");
22
+ break;
23
+ case CLASS_OBJ:
24
+ rbACLType = rb_str_new2("mask");
25
+ break;
26
+ case DEF_USER: case DEF_USER_OBJ:
27
+ rbACLType = rb_str_new2("defaultuser");
28
+ break;
29
+ case DEF_GROUP: case DEF_GROUP_OBJ:
30
+ rbACLType = rb_str_new2("defaultgroup");
31
+ break;
32
+ case DEF_OTHER_OBJ:
33
+ rbACLType = rb_str_new2("defaultother");
34
+ break;
35
+ case DEF_CLASS_OBJ:
36
+ rbACLType = rb_str_new2("defaultmask");
37
+ break;
38
+ default:
39
+ rbACLType = rb_str_new2("unknown");
40
+ }
41
+ return rbACLType;
42
+ }
43
+
44
+ /*
45
+ * Helper function used by the acl_write_text class and instance methods.
46
+ */
47
+ void do_acl_check(int aclcheck_val, int which){
48
+ char err[MAX_STRING];
49
+
50
+ switch(aclcheck_val){
51
+ case 0:
52
+ break; /* Nothing wrong */
53
+ case USER_ERROR:
54
+ sprintf(err,"Invalid ACL entry: %i; Multiple user entries", which);
55
+ rb_raise(cSolarisFileError,err);
56
+ case GRP_ERROR:
57
+ sprintf(err,"Invalid ACL entry: %i; Multiple group entries", which);
58
+ rb_raise(cSolarisFileError,err);
59
+ case OTHER_ERROR:
60
+ sprintf(err,"Invalid ACL entry: %i; Multiple other entries", which);
61
+ rb_raise(cSolarisFileError,err);
62
+ case CLASS_ERROR:
63
+ sprintf(err,"Invalid ACL entry: %i; Multiple mask entries", which);
64
+ rb_raise(cSolarisFileError,err);
65
+ case DUPLICATE_ERROR:
66
+ sprintf(err,"Invalid ACL entry: %i; Multiple user or group entries", which);
67
+ rb_raise(cSolarisFileError,err);
68
+ case ENTRY_ERROR:
69
+ sprintf(err,"Invalid ACL entry: %i; Invalid entry type", which);
70
+ rb_raise(cSolarisFileError,err);
71
+ case MISS_ERROR:
72
+ rb_raise(cSolarisFileError, "Missing ACL entries");
73
+ case MEM_ERROR:
74
+ rb_raise(cSolarisFileError, "Out of memory!");
75
+ default:
76
+ rb_raise(cSolarisFileError, "Unknown error");
77
+ };
78
+ }
@@ -0,0 +1,156 @@
1
+ ###############################################################################
2
+ # tc_solaris_file.rb
3
+ #
4
+ # Test suite for the solaris-file package.
5
+ ###############################################################################
6
+ base = File.basename(Dir.pwd)
7
+
8
+ if base == "test" || base =~ /solaris-file.*/
9
+ require "ftools"
10
+ Dir.chdir("..") if base == "test"
11
+ Dir.mkdir("solaris") unless File.exists?("solaris")
12
+ File.copy("file.so","solaris")
13
+ $LOAD_PATH.unshift(Dir.pwd)
14
+ Dir.chdir("test") rescue nil
15
+ end
16
+
17
+ require "test/unit"
18
+ require "solaris/file"
19
+ require "open3"
20
+
21
+ class TC_Solaris_File < Test::Unit::TestCase
22
+ def setup
23
+ @dir = Dir.pwd
24
+ @file = "foo.txt" # trivial
25
+ @file2 = "bar.txt" # non-trivial
26
+
27
+ @acl_text = "user::rw-,user:nobody:r--,"
28
+ @acl_text << "group::r--,group:sys:r--,mask:r--,other:r--"
29
+
30
+ File.open(@file,"w+"){ |fh| fh.puts "foo" } unless File.exists?(@file)
31
+ File.open(@file2,"w+"){ |fh| fh.puts "bar" } unless File.exists?(@file2)
32
+
33
+ system("setfacl -m #{@acl_text} #{@file2}") # Make @file2 non-trivial
34
+
35
+ @fh = File.open(@file)
36
+ @fh2 = File.open(@file2)
37
+ end
38
+
39
+ def test_version
40
+ assert_equal("0.3.1", File::SOLARIS_VERSION)
41
+ end
42
+
43
+ # CLASS METHODS
44
+
45
+ # This yields an ACL struct for each entry
46
+ def test_class_acl_read
47
+ assert_respond_to(File,:acl_read)
48
+ assert_nothing_raised{ File.acl_read(@file) }
49
+ assert_equal(nil,File.acl_read(@file))
50
+ assert_kind_of(Array,File.acl_read(@file2))
51
+ assert_raises(Errno::ENOENT){ File.acl_read("bogus") }
52
+ assert_raises(ArgumentError){ File.acl_read("bogus"*500) }
53
+ end
54
+
55
+ # Tests the acltotext() approach
56
+ def test_class_acl_read_text
57
+ assert_respond_to(File,:acl_read_text)
58
+ assert_nothing_raised{ File.acl_read_text(@file) }
59
+ assert_kind_of(NilClass,File.acl_read_text(@file))
60
+ assert_kind_of(String,File.acl_read_text(@file2))
61
+ assert_raises(Errno::ENOENT){ File.acl_read_text("bogus") }
62
+ end
63
+
64
+ # Tests the aclfromtext() approach
65
+ def test_class_acl_write_text
66
+ text = "user::rw-,group::r--,mask:r--,other:---"
67
+ assert_respond_to(File,:acl_write_text)
68
+ assert_nothing_raised{ File.acl_write_text(@file,text) }
69
+ assert_raises(File::SolarisError){ File.acl_write_text(@file,"bogus") }
70
+ end
71
+
72
+ def test_class_acl_trivial
73
+ assert_respond_to(File,:trivial?)
74
+ assert_nothing_raised{ File.trivial?(@file) }
75
+ assert_equal(true,File.trivial?(@file))
76
+ assert_equal(false,File.trivial?(@file2))
77
+ assert_raises(Errno::ENOENT){ File.trivial?("bogus") }
78
+ assert_raises(ArgumentError){ File.trivial?("bogus"*500) }
79
+ end
80
+
81
+ def test_class_acl_count
82
+ assert_respond_to(File, :acl_count)
83
+ assert_nothing_raised{ File.acl_count(@file) }
84
+ assert_kind_of(Fixnum, File.acl_count(@file))
85
+ assert_raises(Errno::ENOENT){ File.acl_count("bogus") }
86
+ assert_raises(ArgumentError){ File.acl_count("bogus"*500) }
87
+ end
88
+
89
+ def test_class_realpath
90
+ dir1 = File.dirname(Dir.pwd) + "/examples"
91
+ dir2 = Dir.pwd + "/.././examples"
92
+
93
+ assert_respond_to(File, :realpath)
94
+ assert_nothing_raised{ File.realpath(@dir) }
95
+ assert_equal(@dir, File.realpath(@dir))
96
+ assert_equal(dir1, File.realpath(dir2))
97
+ assert_raises(Errno::ENOENT){ File.realpath("bogus") }
98
+ end
99
+
100
+ def test_class_resolvepath
101
+ assert_respond_to(File, :resolvepath)
102
+ assert_nothing_raised{ File.resolvepath(@dir) }
103
+ assert_equal(@dir, File.resolvepath(@dir))
104
+ assert_equal("../examples", File.resolvepath("../examples"))
105
+ assert_raises(Errno::ENOENT){ File.resolvepath("bogus") }
106
+ end
107
+
108
+ # INSTANCE METHODS
109
+
110
+ def test_instance_acl
111
+ assert_respond_to(@fh, :acl_read)
112
+ assert_nothing_raised{ @fh.acl_read }
113
+ assert_equal(nil, @fh.acl_read)
114
+ assert_kind_of(Array, @fh2.acl_read)
115
+ assert_kind_of(Struct::ACLStruct, @fh2.acl_read.first)
116
+ end
117
+
118
+ # Tests the acltotext() approach
119
+ def test_instance_acl_read_text
120
+ assert_respond_to(@fh,:acl_read_text)
121
+ assert_nothing_raised{ @fh.acl_read_text }
122
+ assert_equal(nil, @fh.acl_read_text)
123
+ assert_kind_of(String, @fh2.acl_read_text)
124
+ end
125
+
126
+ # Tests the aclfromtext() approach
127
+ def test_instance_acl_write_text
128
+ text = "user::rw-,group::r--,mask:r--,other:---"
129
+ assert_respond_to(@fh2,:acl_write_text)
130
+ assert_nothing_raised{ @fh2.acl_write_text(text) }
131
+ assert_raises(File::SolarisError){ @fh2.acl_write_text("bogus") }
132
+ end
133
+
134
+ def test_instance_acl_trivial
135
+ assert_respond_to(@fh, :trivial?)
136
+ assert_nothing_raised{ @fh.trivial? }
137
+ assert_equal(true, @fh.trivial?)
138
+ assert_equal(false, @fh2.trivial?)
139
+ end
140
+
141
+ def test_instance_acl_count
142
+ assert_respond_to(@fh,:acl_count)
143
+ assert_nothing_raised{ @fh.acl_count }
144
+ assert_kind_of(Fixnum,@fh.acl_count)
145
+ assert_equal(0,@fh.acl_count)
146
+ assert_equal(6,@fh2.acl_count)
147
+ end
148
+
149
+ def teardown
150
+ @dir = nil
151
+ @file = nil
152
+ @file2 = nil
153
+ @fh.close
154
+ @fh2.close
155
+ end
156
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: solaris-file
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.3.1
7
+ date: 2006-07-11 00:00:00 -06:00
8
+ summary: ACL and other methods for the File class on Solaris
9
+ require_paths:
10
+ - lib
11
+ email: djberg96@gmail.com
12
+ homepage: http://www.rubyforge.org/projects/sysutils
13
+ rubyforge_project:
14
+ description: ACL and other methods for the File class on Solaris
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Daniel Berger
31
+ files:
32
+ - CHANGES
33
+ - MANIFEST
34
+ - README
35
+ - extconf.rb
36
+ - lib/solaris/sfile.c
37
+ - lib/solaris/sfile.h
38
+ - examples/test.rb
39
+ test_files:
40
+ - test/tc_solaris_file.rb
41
+ rdoc_options: []
42
+
43
+ extra_rdoc_files:
44
+ - CHANGES
45
+ - README
46
+ executables: []
47
+
48
+ extensions:
49
+ - extconf.rb
50
+ requirements: []
51
+
52
+ dependencies: []
53
+