if it is only for a "copy", maybe a scheme like this can be useful:
archive dir. struct without following symlinks (tar zcf ..., or pax)
list symlinks: if relative they are already copied
if not, if file just copy, if dir repeat the process
for the general symlink problem, it might be useful to separate dir part from file-part, and break the dir part by components. First we get the list of symlinks in your hierarchy (from the OS, find or whatever), and then process each element of the list:
for any symlink /a/b/.../y/z is it a dir?
if not then /a/b.../y is a dir!
now we study each path component starting with /a
is /a a symlink? if it is absolute you list, and keep going down the original path, if it is relative you might do the equivalent of the shell
( cd -P $dir || exit 1; echo $PWD) for a start
part of the problem is that some links might be stale or even incorrect
when a pattern like ../dir/../dir2/.. is not OK, so an intermediary readlink helps
just a thought,
--stephan