I recently wrote an AIR application called SPF, or Screen Protection Factor. It’s a screen saver that will fill however many monitors you have attached to your computer with random pictures from a specified directory. The specified directory is recursively traversed so SPF will find all supported file types (jpg, png, and gif), no matter how deeply nested they are.
While writing SPF, I realized that a carelessly placed symbolic link could easily put my directory traversal code into an infinite loop. Symbolic links (as they are known on Unix systems, including OS X) and junction points (as they are known on Windows) are pointers to files or directories which are mostly indistinguishable from whatever they point to. I use them frequently when doing web development when I don’t want to keep my source code in my web root. Instead, I create a symbolic link in my web root which points to my source tree, and assuming my web server is configured correctly, it’s just like having the same code in two places. Put a symbolic link in the wrong place, however, and you’ve created a circular reference on the file system. Normally this isn’t a problem, until you have a piece of code that is recursively traversing that portion of your file system.
I tried a few stopgap measures to guard against circular references in my SPF code, but there really was no way to gracefully handle the problem without specific APIs. Fortunately, those APIs now exist.
To handle symbolic links, you need two File APIs: the
isSymbolicLink property, and the
isSymbolicLink simply returns a boolean which tells you if the File instance is a symbolic link or a junction point. Simple enough. But what does the symbolic link actually point to? That’s where
canonicalize comes in. Call
canonicalize, and suddenly the file reference now points to the actual file referenced by the link. Call
nativePath, and you get the path of the original file, not the link.
So how does this solve my SPF problem? While traversing the file system, I keep a map of file paths, and before adding a new image to the queue, I check to see if it is already in the map. Before I was able to resolve symbolic links, a circular reference would have me adding the same files infinitely because the path continued to grow. Now, I simply check to see if the file reference is a symbolic link, and if it is, I call
canonicalize before adding it to the map. Problem solved.
These two APIs don’t work on Mac aliases or Windows shortcuts, however they don’t have to. AIR will not follow aliases or shortcuts like it will symbolic links, so they cannot get you into the same kind of trouble.