Create a shared mounted volume for all users of a Mac

Mar 01, '10 07:30:00AM

Contributed by: trosberg

The motivation for this hint was to have one folder for common use, with read and write privileges for every user. In Mac OS X, the Shared directory can be used by all users. However, a file there is still owned by the user who put it there. Another user cannot edit the file without authentication. This hint creates a common volume named AppleBasket, where users can have files in common.

In practice, an encrypted disk image mounting automatically for every user is a good solution to this problem. The following AppleScript automates the unixy requirements in creating such a disk image. Here's the script:

(*
AppleBasket 1.0

Creates a common volume for all users.

Motivation for the script was to have a folder for common use, with read and write privileges for every user.
Tested with Mac OS X 10.4., 10.5 and 10.6. Requires launchd (appeared in Mac OS X 10.4).
Tuomas Rosberg 2010. Paste into a new document in AppleScript Editor, run from there or save as an application.
*)

-- To install or to uninstall:
tell application "System Events"
  set pListList to every item in folder "/Library/LaunchAgents/" whose name contains "AppleBasket"
  if pListList is not {} then
    set sList to {}
    repeat with i in pListList
      set s to POSIX path of i
      set sList to sList & s
    end repeat
    my Choices(sList)
  else -- pListList was empty.
    my CreateImage()
  end if
end tell
on Choices(sList)
  display dialog ¬
    "A job by this script already exists. Do You want to uninstall the job or proceed to new one?" buttons {"Uninstall", "Proceed"} default button "Uninstall"
  set theResult to button returned of the result
  if theResult is "Uninstall" then
    do shell script "sudo launchctl unload /Library/LaunchAgents/" with administrator privileges
    repeat with i in sList
      do shell script "sudo rm -f " & i with administrator privileges
    end repeat
    display dialog ¬
      "“AppleBasket” job has been uninstalled. Please log out and in." buttons "Quit" default button 1
  else -- the result is "Proceed".
    my CreateImage()
  end if
end Choices

-- Installing:
on CreateImage()
  -- To compile a unique name for the common volume:
  tell application "System Events"
    set aList to every item in folder "/" whose name contains "AppleBasket"
    set aList to aList & (every item in folder "/Users/" whose name contains "AppleBasket") -- In case of this script being used before.
  end tell
  set n to count aList
  if n is 0 then
    set n to ""
  end if
  set imageName to "AppleBasket" & n as text
  -- Info for the user:  
  display dialog ¬
    "The script will create “AppleBasket”, a common volume, readable and writable for every user, in directory /Users." & return & return & ¬
    "Next you will be asked for a password. Every user of the volume needs to enter it. (Only once if they save it in their Keychain.)" buttons {"Cancel", "OK"} default button "OK" with icon note
  if button returned of result is "OK" then
    display dialog ¬
      "Please give a password used for accessing “AppleBasket”. " default answer "Common Volume" buttons "OK" default button "OK"
    set pWord to text returned of the result
    display dialog ¬
      "The password for “AppleBasket” is “" & pWord & "”" & return & return & ¬
      "Write it down to help your memory!" buttons "OK" default button "OK" with icon note
    display dialog "To create common volume for every user you will be asked to authenticate as an administrator." & return & return & ¬
      "Create disk image " & imageName & "?" buttons {"Cancel", "OK"} default button "OK" with icon caution
    -- Action: Create an image of 1 GB volume owned by root:
    do shell script "sudo printf \"" & pWord & "\\0\" | hdiutil create -volname \"" & imageName & "\" -size 1g -type SPARSE -fs HFS+J -encryption AES-128 -stdinpass \"" & imageName & "\"" with administrator privileges
    tell application "Finder"
      activate
      set fileName to imageName & ".sparseimage"
      if (exists of file fileName of startup disk) is true then -- this tests success of previous "do shell script", may be too abundant.
        my MountCommands(fileName)
      end if
    end tell
  end if
end CreateImage

on MountCommands(fileName)
  -- Move the disk image:
  do shell script "mv -nv '" & fileName & "' /Users/" with administrator privileges
  -- Give disk image read and write permission for all users:
  do shell script "chmod 777 '/Users/" & fileName & "'" with administrator privileges
  -- Ready to write a preference list:
  set homeFolder to path to home folder as string
  set plistName to "org.AppleBasket.mount.plist"
  set newPlist to homeFolder & plistName -- A path string
  open for access newPlist with write permission -- Creates a new file, if it doesn't exist.
  set f to result
  write "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
  <key>Label</key>
  <string>org.AppleBasket.mount</string>
  <key>OnDemand</key>
  <true/>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/hdiutil</string>
    <string>attach</string>
    <string>/Users/" & fileName & "</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>WatchPaths</key>
  <array>
    <string>/Volumes/</string>
  </array>
</dict>
</plist>" to f
  close access f
  -- The administrator stuff to make the job work:
  set newPlist to POSIX path of newPlist
  -- Unload launchd jobs of /Library:
  try
    do shell script "launchctl unload /Library/LaunchAgents/" with administrator privileges
  end try
  -- Move the plist to a folder watched by the system starter, launchd:
  do shell script "mv -f " & newPlist & " /Library/LaunchAgents/" with administrator privileges
  -- Change ownership of the plist to system and group to admin:
  do shell script "chown root:admin /Library/LaunchAgents/" & plistName with administrator privileges
  -- Change mode of file to read for all, execute for none:
  do shell script "chmod 644 /Library/LaunchAgents/" & plistName with administrator privileges
  -- Load launchd jobs of /Library:
  do shell script "launchctl load /Library/LaunchAgents/" with administrator privileges
  activate me
  display dialog "A per-user job for every user has been installed to mount of the common volume automatically. Please log out and in." buttons "Quit" default button 1
end MountCommands
Paste into a new document in AppleScript Editor, run from there or save as an application. AppleScript was chosen so that I could make a (spartan) user interface. Any other scripting language would be much easier to debug, but AppleScript was all I tinkered with on Mac OS 9, before having kids and real life. To make a bigger disk image, edit the -size variable to something larger, like 10g.

Note that if Fast User Switching is in use and the AppleBasket volume is mounted for a user other than current one, there will be problems.

The script may be useful for a family Mac. Alternatively, one can set up an external hard drive or some storage cloud for every user of their Mac, of course.

[robg adds: I haven't tested this one. You may want to check the original source of the script, to see if anything has changed since this hint was published.]

Comments (12)


Mac OS X Hints
http://hints.macworld.com/article.php?story=20100226131631825