The Arctic Mac

Install CS5 on a case-sensitive file system

Motivation

For years, Adobe's Creative Suite hasn't behaved well with case-sensitive file systems. Essentially this is sloppy programming - files are named with one convention and referred to with a different one, and the programmer relies on the case-preserving but case-insensitive nature of HFS to make sure everything works. Many of us have entertained hopes that Adobe would fix this problem - it's not very hard, since all you have to do is rename (or re-reference) some files. Sometime around CS4 or CS5, Adobe did come up with a "fix" for the problem - they just made the requirement official and added a couple of lines to the installer so that it will refuse to install on a case-sensitive system. Combined with their requirement that you install on a boot partition, this means you're pretty much unable to use the CS apps if you formatted your root partition as case-sensitive. Their official work around is to backup your system and reinstall from scratch on a case-insensitive file system. Great.

Of course, the best option would simply be to swear you'll never give another dime to a software companies with such ridiculous policies (they want you, a high-paying customer, to take hours of your time to redo your whole setup to work with their apps when they could have fixed the problem the right way in about the same amount of time it probably took them to make the new checks in the installer). There are a lot of other good pieces of software out there (Pixelmator, Acorn, Gimp, Inkscape to name a a few) But if you really need to work with the Adobe apps (e.g. to be able to collaborate with others who use them), there's not a whole lot you can do about that.

While you may find another solution that works better for you (such as adding a second partition on your hard drive, or running the CS apps in VirtualBox under 10.7), I was hoping to go back to the old way of just renaming all the necessary files so that the software will run normally off of the case-sensitive file system. The biggest disadvantage to this approach is that you may have to rename some of the files again after you run updates. While writing this up, I did find another method that is quite a bit more elegant, but I thought I might share my method as well in the hopes that it may be instructive.

Before you get started, you'll need to have the developer tools installed because the procedure relies heavily on GDB (the GNU debugger). Basically what we're going to do is to use the debugger to trick the installer into thinking that our boot partition is case-insensitive, then after it copies over all the files, we'll rename/symlink as necessary to get things to work. I've provided a script that should take care of most of the renaming for Photoshop and Illustrator (the two I use), but you may have a bit of your own work to do for the other apps.

The Pre-installer

The first step is to start the CS5 installer via gdb with root permissions (root permissions are important because we lose our ability to trick the installer if it elevates its own permissions instead of starting out that way). To do so, open a terminal and run

sudo gdb pathToInstaller.app/Contents/MacOS/Installer

then enter your password. Once in gdb, we need to set up a breakpoint before we proceed:

break FSGetVolumeParms

(when I do that, it asks me if I want to make a pending breakpoint, to which the correct answer is yes). Then we'll have it automatically run some commands every time it hits the breakpoint:

commands 1 set $myaddr = (*(unsigned long *)($ebp+0xc)+0x14) finish end

Finally type 'run' to start the program. This program's job is actually to run a couple of checks, then install and start the main installer GUI. The debugger will stop several times when it gets to the breakpoint. Each time it does so, you should paste in these two lines:

set *$myaddr = (*(unsigned long*)$myaddr)&0xffafffff continue

Once the progress bar appears, you've successfully tricked this part of the installer. The next time it stops, you can type this, and then it will finish without any more pauses:

disable 1 continue

The GUI installer

Now, you're on into the main GUI installer. As long as you're fine installing into /Applications, you don't need any trickery for most of this part here. Just proceed through the installer until you've selected the components you're going to install, but don't click that last "Install" button yet, because you need to get ready.

If you do want to change the install location, you'll need to figure out the PID of the GUI app (it's named PDApp) using Activity Monitor or your tool of choice, and then attach gdb to it. sudo gdb in a new shell, then attach pid once you're in gdb. Then follow the same instructions you did above to convince the GUI that it's okay for you to install in your alternative location.

Once you're ready to click the install button, move on to the next part:

The Installer Worker

There is a third program, named "Setup" that runs hidden and does all the actual work of the install, reporting it's progress back to PDApp. It turns out that it does one more check before performing the installation. Since it doesn't have a GUI, we need to catch it in gdb immediately on launch. This is where we're glad that we started out with root permissions, because otherwise Setup would just start another copy of itself with elevated permissions, and it turns out to be very difficult to catch that in a debugger. Fortunately, we thought ahead, so our job is easier. Open a new Terminal window, and do:

sudo gdb

Once in gdb,

attach -waitfor Setup

Now you can go and click the install button, and the new copy of GDB will attach as soon as the Setup process starts. The GUI installer will show an indeterminate progress bar. Now you need to jump through the same hoops as above to trick the hidden installer into thinking it's okay to proceed. Once the progress bar changes to a determinate one, you've succeeded. This time, when you're done, instead of disabling the breakpoint and continuing running with gdb attached (which will slow down the install), you can just detach in gdb, and Setup will finish up.

Fixing Case

By various methods (watching for console errors about missing libraries, and using dtrace to look at the files that the apps try to access when you run them), it is possible to figure out what filenames are expected, and then compare them to the ones already on disk. I've done that work (as far as I have found so far) for Photoshop and Illustrator, and I've captured the results in the script below. To use it, save it to a file (e.g. on the Desktop called fix_case.pl), then give it execute permissions:

cd ~/Desktop chmod +x fix_case.pl

Then run it once each on photoshop and illustrator:

./fix_case.pl /Applications/Adobe\ Photoshop\ CS5/Adobe\ Photoshop.app ./fix_case.pl /Applications/Adobe\ Illustrator\ CS5/Adobe\ Illustrator.app

If you installed other apps from the CS suite, the script may be useful to you to help with them, but there's a good chance you'll need to do some more things to get them fully working. The nice thing about having them in a script is that when adobe pushes an update that has the incorrectly named files in it, you can just re-run the script and things should work again.

Here's the script I have

#!/usr/bin/perl my $app = shift; print "working on app: $app\n"; chdir "$app/Contents/Frameworks"; print "fixing frameworks\n"; my $tofix = `find . -name a -type d`; foreach $dir (split(/\n/,$tofix)) { $newpath = $dir; $newpath =~ s/a$/A/; print "mv $dir $newpath\n"; `mv "$dir" "$newpath"`; } $tofix = `find . -name resources -type d`; foreach $dir (split(/\n/,$tofix)) { $newpath = $dir; $newpath =~ s/resources$/Resources/; print "mv $dir $newpath\n"; `mv "$dir" "$newpath"`; } $tofix = `find . -name english.lproj -type d`; foreach $dir (split(/\n/,$tofix)) { $newpath = $dir; $newpath =~ s/english.lproj$/English.lproj/; print "mv $dir $newpath\n"; `mv "$dir" "$newpath"`; } if (-e "adobelinguistic.framework") { print "renaming adobelinguistic.framework\n"; rename "adobelinguistic.framework", "AdobeLinguistic.framework"; } if (-e "wrservices.framework") { print "renaming wrservices.framework\n"; rename "wrservices.framework", "WRServices.framework"; } if (-e "adobejp2k.framework") { print "renaming adobejp2k.framework\n"; rename "adobejp2k.framework", "AdobeJP2K.framework"; } if (-e "updaternotifications.framework") { print "renaming UpdaterNotifications.framework\n"; rename "updaternotifications.framework", "UpdaterNotifications.framework"; } if (!(-e "adobepdfsettings.framework/Versions/A/adobepdfsettings")) { print "linking adobepdfsettings.framework\n"; symlink "AdobePDFSettings", "adobepdfsettings.framework/Versions/A/adobepdfsettings"; } if (!(-e "AdobeBIBUtils.framework")) { print "renaming AdobeBibUtils.framework\n"; rename "AdobeBibUtils.framework", "AdobeBIBUtils.framework"; } if (!(-e "adbeape.framework")) { print "renaming Adbeape.framework\n"; rename "Adbeape.framework", "adbeape.framework"; } if (!(-e "Adobe_OOBE_Launcher.framework")) { print "linking adobe_oobe_launcher.framework\n"; symlink "adobe_oobe_launcher.framework", "Adobe_OOBE_Launcher.framework"; symlink "adobe_oobe_launcher", "adobe_oobe_launcher.framework/Adobe_OOBE_Launcher"; } if ($app =~ /Illustrator/) { if(!(-e "AdobePDFSettings.Framework")) { print "linking AdobePDFSettings.Framework\n"; symlink "AdobePDFSettings.framework", "AdobePDFSettings.Framework"; } chdir "../.."; if(!(-e "Required/Resources/en_US/PluginRes.aip")) { print "linking PlugInRes.aip\n"; symlink "PlugInRes.aip", "Required/Resources/en_US/PluginRes.aip"; } }
Contact The ArcticMac