private static String getRelativeLink( String fromDir, String toDir )
        throws IOException
    {
        StringBuffer toLink = new StringBuffer();   // up from fromDir
        StringBuffer fromLink = new StringBuffer(); // down into toDir

        // create a List of toDir's parent directories
        List parents = new LinkedList();
        File f = new File( toDir );
        f = f.getCanonicalFile();
        while ( f != null )
        {
            parents.add( f );
            f = f.getParentFile();
        }

        // walk up fromDir to find the common parent
        f = new File( fromDir );
        if ( !f.isDirectory() )
        {
            // Passed in a fromDir with a filename on the end - strip it
            f = f.getParentFile();
        }
        f = f.getCanonicalFile();
        f = f.getParentFile();
        boolean found = false;
        while ( f != null && !found )
        {
            for ( int i = 0; i < parents.size(); ++i )
            {
                File parent = (File) parents.get( i );
                if ( f.equals( parent ) )
                {
                    // when we find the common parent, add the subdirectories
                    // down to toDir itself
                    for ( int j = 0; j < i; ++j )
                    {
                        File p = (File) parents.get( j );
                        toLink.insert( 0, p.getName() + "/" );
                    }
                    found = true;
                    break;
                }
            }
            f = f.getParentFile();
            fromLink.append( "../" );
        }

        if ( !found )
        {
            throw new FileNotFoundException( fromDir + " and " + toDir + " have no common parent." );
        }

        return fromLink.append( toLink.toString() ).toString();
    }