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.
精彩评论