check and change folder permissions

Hello,

My first post! here goes… I have been trying to find a solution to this but have not been successful…

I would like to check the permissions of a folder and if its read only, then change the permissions to read and write, and vice versa. Basically having an applescript to toggle permissions of a given folder.

I have found this which can change the folder to read and write:

do shell script "chmod -R u+wr /Users/myhomefolder/afolder/anotherfolder"

but i think i now need an ‘if’ statement before this line and also the reverse of this (im not sure what the read only version of u+wr is)

any help would be greatly appreciated.

thanks

Lee

Model: PowerMac G5
Browser: Firefox 3.1b3
Operating System: Mac OS X (10.5)

First, it sounds like you already noticed that the script you quoted does more than you specified (toggle between read-only and read+write). In addition to changing the permission from read-only to read+write, the “+rw” syntax in chmod also changes write-only to read+write and neither-read-nor-write to read+write. Maybe this is OK for you, but you should be aware of the difference between what you said you wanted and what the code you posted actually does.

Another difference from what you describe versus what the script does revolves around the “-R” option. This option makes chmod act on the specified path and all paths contained therein (it is the recursive option). This makes the chmod command affect not only the specified folder but also all of its files and subfolders (and their files and subfolders (and their files and subfolders (and .))). If you do not want all the transitively contained files and subfolders changed, then do not use “-R”.

The obvious reverse of “+rw” is “-rw”, but that would remove read permissions (leaving it as neither-read-nor-write). You probably want “-w” (only removes the write permission), or “+r-w” (always add read permission, and remove write permission). The later is the best option if you want to always make sure the folder (and its contents, since “-R” is used) is readable. If you want to be able to toggle read-only to read+write and neither-read-nor-write to write-only (and back), then “+w”/“-w” is a better paring, since they would never change the read permission.

Additionally, the recursive option complicates the interpretation of your specification. Do you want the folder and each of its files/subfolders “toggled” independently or should they all follow the main folder (i.e. all go read-only when the main folder goes read-only, even if some were read-only to begin with)?

Assuming that you want all the contents to follow the “main folder”, and that you do not care to preserve write-only or neither-read-nor-write permissions, the folllowing might do what you want:

set quotedPath to quoted form of "/Users/myhomefolder/afolder/anotherfolder"
set cmd to "
if test -w " & quotedPath & "
then
    chmod -R u+r-w " & quotedPath & "
else
    chmod -R u+rw " & quotedPath & "
fi"
do shell script cmd

Hi Chris,

thanks for your reply - the explanation was very helpful, and you are right. I have simplified my original script to instead of the u+wr to toggle between 755 (normal permissions) and 330 (drop box). Also, you are correct, i do not need the recursive function.

so…

i have created 2 separate scripts that work as needed, but i would now like to put them into one script.

do shell script "chmod 330 /Users/myhomefolder/afolder/anotherfolder"
do shell script "chmod 755 /Users/myhomefolder/afolder/anotherfolder"

the script you included didnt quite work as intended, and i tried changing the u+rw bits to 755 etc, but that didnt work either. Could you help me to modify your script to work like this?

out of curiosity the way that i thought it would work is something along these lines - would it work?

if "/Users/myhomefolder/afolder/anotherfolder" is 755 then
do shell script "chmod 330 /Users/myhomefolder/afolder/anotherfolder"
else
do shell script "chmod 755 /Users/myhomefolder/afolder/anotherfolder"
end if

thanks for your time

Lee

Yes, this is greatly simplified. Thank you for taking the time to think about what you really need and not just “cargo culting” some code that seems like it might do what you want.

That general pattern can be made to work fairly easily. In the code below, I use stat to extract the current mode bits (which include the permission bits).

The other changes in the code below are the extraction of the path string into a variable and the use of quoted form of. Using a variable saves on typing and prevents the problem of having a typo (or intentional edit) in some, but not all, of the strings. This follows the DRY principle.

I included quoted form of because it is always a good idea to quote arguments to shell programs. This is especially important to do when using dynamic strings (those provided by the user or other programs), but it does not hurt to apply it to your own static strings (such as the “hard coded” path in your program). Applying it to the static strings means that you do not need to vet the strings (e.g. paths) for shell metacharacters (like spaces, tabs, greater-than, less-than, ampersand, semicolon, etc.). More importantly, whoever might need to modify the script later to point to a different path does not have to keep in mind that they should also do such vetting. Since the script takes care to properly quote the string argument (via quoted form of), the maintenance crew can simply update the string without having to think about how it is used later.

set quotedPath to quoted form of "/Users/myhomefolder/afolder/anotherfolder"

do shell script "stat -f %p " & quotedPath
if result is "40755" then
	do shell script "chmod 330 " & quotedPath
else
	do shell script "chmod 755 " & quotedPath
end if

The “4” in “40755” is part of the “mode bits” that tells us that the path is a directory and not a plain file or some other kind of special file (symlink, fifo, device node, etc.).

The “0” in “40755” means that neither the set-uid, the set-gid, nor the “sticky” bit is set for the path. These bits are usually not set, but the set-gid and “sticky” bits do have meaning for directories. When you give chmod strings like 755 and 330 to use as mode strings, they are actually interpreted as octal numbers (each digit represents three bits: read, write, and execute permissions; one digit each for user-owner, group-owner and “other”). But since this extra digit is a leading digit, it is taken as zero unless it is specified (like 4555 for a typical set-uid executable).

The above code is a literal implementation of your pseudocode (well only the if was pseudocode-ish), but I do have some more thoughts if you care to consider them.

Further Thoughts
Your two modes, 755 and 330, can be written symbolically as rwxr-xr-x and -wx-wx—. First a comment on why my previous script did not work with your modes, then some comments on some possible permission inconsistencies across the two modes.

Why test -w does not work to test between 755 and 330
My previous script used the shell code test -w path for the conditional expression. That would work for read+write vs. read-only, but the “dropbox” mode here is not read-only, it is actually more like write-only (it is write-only except for the execute bits). So if the 755 and 330 permissions were used in my previous script, the folder would always be writable (to the owner), so the if would never take the false branch.

Also, the ‘-w’ test might not have been the best one since it does not test any single “write bit”, but a sort of combination of all three (it uses the user-owner write bit if the accessing process’s uid matches the file’s user-owner, otherwise it uses the group-owner “write bit” if the accessing process’s gid matches the file’s group-owner, otherwise it uses the ‘other’ “write bit”; this is basically how the three-level permission system works in UNIX-iod systems).

Potential Inconsistencies between 755 and 330
The first potential inconsistency I see here arises if both of these modes are used in the same “environment” (file sharing status, remote login status, etc.). If both the normal and dropbox permissions might be used when the directory would be accessible to ‘other’ processes (those not with a uid that matches the directory’s user-owner nor a gid that matches the directory’s group-owner), then it might make sense to either expand the dropbox permissions (to XX3; ‘other’ can drop files in dropbox mode and read files in normal mode) or contract the normal permissions (to XX0; other can not access in either mode).

The second possible inconsistency is for the user-owner. The user permissions change from read+write+chdir in normal mode to write+chdir in dropbox mode. This means that the user that owns the directory will not be able to see the contents of the directory while it is in dropbox mode. This might be intentional to try to simulate being an “outsider”, but could also be frustrating if the owner needs to wait for some file to show up and has no “out of band” way to know if the file has been “dropped” (i.e. other than Finder or ls -l path/to/the/dir, both of which would be useless unless the user is root (most permission bits are ignored for root!)). It might be better to expand the dropbox mode permissions for the user-owner (to 7XX; owner can always read the directory), or to contract the normal mode permissions for the user-owner (to 5XX; no one (except for root) can write to the directory (not even the owner)).

Some Consistent Permission Pairs
Depending on what you are actually doing, there may be no inconsistency. If above arguments hold sway, however, there are several pairs of permissions that are consistent (at least according to the above arguments).

If the droppers and the readers will always be members of the directory’s group, and you want the owner to always be able to read the directory, use 750 and 730.

If the file droppers (but not the readers) will always be members of the directory’s group, and you want the owner to always be able to read the directory, use 755 and 730. This leaves the directory readable to ‘other’ in normal mode, but not in dropbox mode.

If the file droppers and the readers will never be members of the directory’s group, and you want the owner to always be able to read the directory, use 755 and 733.

If you want to simulate the group/other permissions even if it is the owner accessing the directory, then use 555 and 333 (or 550 and 330 if all of the accesses will be done as a member of the directory’s group).

To integrate any of these into the above script, just ad “40” to one of the permission triples and use that as the comparison value in the if statement.

Hi Chris,

thanks a lot for al your help - the modified script you have supplied makes a lot of sense to me now you have included the detailed description. I recognise the importance of DRY - i have come used similar variables in web programming.

I take your further points about the permissions too and have decided that for my needs 733 and 333 will be best. this is because the folder in question i want to always be a drop box (for my admin account or any other) and sometimes i want access to the folder myself.

This has opened up an interest in applescript, so i have started to add a couple of things to the script, mainly a way of knowing if the script just opened or closed the folder without checking. Here is my final script:

set quotedPath to quoted form of "/Users/myhomefolder/afolder/anotherfolder"

do shell script "stat -f %p " & quotedPath
if result is "40733" then
	do shell script "chmod 333 " & quotedPath
	display dialog ("Library : CLOSED") buttons {"OK"} default button {"OK"} with icon caution giving up after 3
	
else
	do shell script "chmod 733 " & quotedPath
	display dialog ("Library : OPEN") buttons {"OK"} default button {"OK"} with icon caution giving up after 3
	
end if

Thanks again for all your help

Lee

Amazing. I was looking for a script to Batch Change Info on a group of folders and THIS works faster, more elegantly and more thoroughly. Thanks very much!