Creating a ZIP with a Folder-Icon for OS X

Posted on

A few days ago I wanted to send a ZIP to a customer and I wanted the root-folder to have an icon, so it’s visually distinguishable as a “special” folder in the user’s home-directory.

However, zipping a folder with a set icon and then extracting it somewhere else doesn’t restore the icon properly. Here’s one way to fix this.

OS X saves icons in a resource fork and extended attributes. See this KB-entry on setting an icon for a folder.

After you’ve set an icon, the folder will look like that:

seb@zhuk:~/Folder$ ls -al@
total 3912
drwxr-xr-x@  2 seb  staff   102 12 Jun 13:51 .
    com.apple.FinderInfo      32 
drwxr-xr-x+ 68 seb  staff  3978 12 Jun 13:51 ..
-rw-r--r--@  1 seb  staff     0 12 Jun 13:51 Icon?
    com.apple.FinderInfo      32 
    com.apple.ResourceFork    40625

As you can see, the icon is saved in a resource fork, there’s a special file Icon\r and there are extended attributes on that file and on “.”. Rather complicated, but that’s how it is.

First, we need to ZIP it in a way that resource forks and extended attributes are preserved. Command line ZIP and e.g. Archiver don’t do that, but OS X’s Archive Utility does. In 10.7, it doesn’t shop up in Applications and is not indexed by Spotlight, so start it by calling

open /System/Library/CoreServices/Archive\ Utility.app/

In later versions (tested on 10.11) it can be found with Spotlight.

Then, configure it to create ZIP-files and zip the folder with the icon. If you decompress this folder somewhere else, you’ll see that there’s no icon displayed by Finder. If you do a ls -al@ on the decompressed folder you’ll find that the extended attribute com.apple.FinderInfo is missing on the top-level directory.

I don’t know why Archive Utility doesn’t zip it. I don’t think it’s for security reasons, as it happily extracts it if it’s present, as we’ll see later.

If we list the contents with command-line-ZIP, it will look like that:

seb@zhuk:~$ zip -Tv Folder.zip 
Archive:  Folder.zip
    testing: Folder/                  OK
    testing: Folder/Icon^M            OK
    testing: __MACOSX/                OK
    testing: __MACOSX/Folder/         OK
    testing: __MACOSX/Folder/._Icon^M   OK
No errors detected in compressed data of Folder.zip.
test of Folder.zip OK

So, resource forks and extended attributes are saved to a __MACOSX-folder, as every Windows-user knows if they’ve ever extracted ZIPs from a Mac.

If there’s a subdirectory with an icon, Archive Utility happily saves everything and the icon will show after extraction. That’s how I found out what’s missing to make sure the extended attribute com.apple.FinderInfo will also be put in place for the top-level-directory.

What is needed in this case is a file called __MACOSX/._Folder with contents that restore the com.apple.FinderInfo-attribute. It’s a file with 82 bytes in size.

With this small Python-script I’ve called osx-iconize-zip-folder.py it can be done:

#!/usr/bin/env python
 
import zipfile, sys
 
finderInfoXattr = [
     0,  5, 22,  7,  0,  2,  0,  0, 77, 97, 99, 32, 79, 83, 32, 88,
    32, 32, 32, 32, 32, 32, 32, 32,  0,  2,  0,  0,  0,  9,  0,  0,
     0, 50,  0,  0,  0, 32,  0,  0,  0,  2,  0,  0,  0, 82,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0, 
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 
     0,  0
]
 
z = zipfile.ZipFile( sys.argv[1], "a" )
 
rootName = z.namelist()[0].strip( "/" )
destFile = "__MACOSX/._" + rootName
 
print "Root directory is '" + rootName + "'"
print "Putting com.apple.FinderInfo data to '" + destFile + "'"
 
z.writestr( destFile, str( bytearray( finderInfoXattr ) ) );

Then, we can do this:

seb@zhuk:~$ ./osx-iconize-zip-folder.py Folder.zip
Root directory is 'Folder'
Putting com.apple.FinderInfo data to '__MACOSX/._Folder'
seb@zhuk:~$ zip -Tv Folder.zip 
Archive:  Folder.zip
    testing: Folder/                  OK
    testing: Folder/Icon^M            OK
    testing: __MACOSX/                OK
    testing: __MACOSX/Folder/         OK
    testing: __MACOSX/Folder/._Icon^M   OK
    testing: __MACOSX/._Folder        OK
No errors detected in compressed data of Folder.zip.
test of Folder.zip OK

Extract the resulting Folder.zip somewhere and the folder will have an icon, hurra!

The above was done on OS X 10.7, but it’s probably the same for newer versions. The Python that comes with it is version 2.7.1.