solaris-file 0.3.1

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