开发者

Is there a better way to read ACLs in Ruby than parsing ls output?

On Mac OS X, ls and chmod hav开发者_StackOverflow中文版e some extra features for handling the ACL permissions that the OS layers on top of the default posix permissions. I have some permission problems that need fixing, and I wrote a script to help patch up these problems until Apple fix that bug. Here's the code that parses ls to get the the ACL:

result = `#{Escape.shell_command(["ls", "-led", file])}`
if result.empty?
    # ls error...
else
    @acl = result.split("\n")[1..-1].collect do |ace|
        ace = ace.split(": ", 2)
        ace[0] = ace[0].to_i
        ace
    end
    # acl processing code...
end

I added the escape gem, but it's still virtually the same code.

But I know it's a bad idea in general to parse ls in a script, so is there a better way to read the ACL permissions from a file?

I need the ACEs and their indices to use with chmod later on in the script:

system("chmod -a# #{index} \"#{file}\"")


Is this what you're after?

File.chmod(0644, path)              # Sets the file to 0644
printf("%o", File.stat(path).mode)  # Returns the mode as an 
                                    # integer and is converted to octal
100644 => nil 


how about lstat?

>> File.lstat('file')
=> #<File::Stat dev=0x803, ino=3365, mode=0100644, nlink=1, uid=0, gid=0, rdev=0x0, size=1328, blksize=4096, blocks=8, atime=2011-03-30 08:39:30 +0800, mtime=2011-03-30 08:36:34 +0800, ctime=2011-03-30 08:36:34 +0800>
>> print "%o" % ( File.lstat('file').mode & 0777  )
644

The above means the file called "file" has permission of 644.


As far as I can tell, there isn't really a better option. ACLs don't seem to be exposed to OSA by the Finder or System Events, so appscript won't help. You could use FFI and the POSIX ACL functions, but the API at that level is exceedingly annoying.


I'm looking through the Ruby 1.8.7 File class. If my one-minute reading is correct, what I gather is that the permissions of the process will govern what you can see from the file, which is exactly what ls will do.

So, if the Ruby script is running as root, it can get all kinds of info about a file, but if it is running as a user, and that user is not in the file's group, and the file is not world-readable for example, then the script cannot see that file.

It seems like if you are running a script as a certain user, and you want to change a file's permissions, you can gather them up and change them with Ruby 1.8.7's chmod in the above link, no?


I created a gem to do ACL reading and modifications:

>> require 'acl'
=> true
>> acl = OSX::ACL.of("tmp")
=> #<OSX::ACL:0x007f92eaabc578 @path="tmp">
>> acl.entries
=> [#<OSX::ACL::Entry:0x007f92eaaf7510 @components=["user", "FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000046", "_www", "70", "allow", "read"]>]
>> ace = acl.entries.first
=> #<OSX::ACL::Entry:0x007f92eaaf7510 @components=["user", "FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000046", "_www", "70", "allow", "read"]>
>> ace.assignment
=> #<OSX::ACL::Assignment:0x007f92ea2a0060 @type="user", @uuid="FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000046", @name="_www", @id="70">
>> ace.assignment.type
=> "user"
>> ace.assignment.name
=> "_www"
>> ace.rules
=> ["allow"]
>> ace.permissions
=> ["read"]
>> acl.remove_entry_at_index(0)
chmod -a# 0 tmp # user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000046:_www:70:allow:read
=> true


This sounds like a job for IRB. (Type irb at the command line). If you don't already, you should consider using IRB if you're writing Ruby, and/or rails console if you're writing a Ruby on Rails application. When you launch the latter at the root of a Rails application, you will load IRB with all (or most) of the code associated with your Rails app.

I made two files, "file_1.txt" and "file_2.txt". As user "charlie", I open up an IRB shell from the directory where these files are located, and played around with Ruby's File class on those two files:

-rw-r--r--  1 root     staff  30 Mar 22 09:06 file_1.txt
-rwxrwxrwx  1 charlie  staff  16 Mar 22 09:06 file_2.txt

charlie:stackoverflow charlie$ man ls
charlie:stackoverflow charlie$ irb
ruby-1.8.7-p330 :001 > File.writable?("file_1.txt")
=> false 

Then, I did the same as root:

irb(main):002:0> File.writable?("file_1.txt")
=> true
irb(main):003:0> File.writable?("file_2.txt")
=> true
irb(main):004:0> 

That's my modus operandi, to learn what I need to do, and I hope that helps answer your question.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜