goto end;
}
- /* Do not dereference absolute symlinks, but copy them "as is".
- * For a relative symlink, we don't know how to properly change it when
- * copied/moved to another dir to keep pointing it to same target as
- * a relative symlink, so we turn it into absolute symlink using
- * realpath() instead. */
- struct stat st;
- if (lstat_utf8(sl, &st) && S_ISLNK(st.st_mode))
- {
- gchar *link_target;
- ssize_t i;
-
- link_target = g_malloc(st.st_size + 1);
- i = readlink(sl, link_target, st.st_size);
- if (i<0)
- {
- g_free(link_target);
- goto orig_copy; // try a "normal" copy
- }
- link_target[st.st_size] = '\0';
-
- if (link_target[0] != G_DIR_SEPARATOR) // if it is a relative symlink
- {
- gchar *absolute;
-
- char *lastslash = strrchr(sl, G_DIR_SEPARATOR);
- int len = lastslash - sl + 1;
-
- int path_max;
-#ifdef PATH_MAX
- path_max = PATH_MAX;
-#else
- path_max = pathconf(sl, _PC_PATH_MAX);
- if (path_max <= 0)
- path_max = 4096;
-#endif
-
- absolute = g_malloc(path_max + 1);
-
- strncpy(absolute, sl, len);
- strcpy(absolute + len, link_target);
- strcpy(link_target, absolute);
-
- char *realPath;
- realPath = realpath(link_target, absolute);
-
- if (realPath != NULL) // successfully resolved into an absolute path
- {
- g_free(link_target);
- link_target = absolute;
- }
- else // could not get absolute path, got some error instead
- {
- g_free(link_target);
- g_free(absolute);
- goto orig_copy; // so try a "normal" copy
- }
- }
-
- if (stat_utf8(tl, &st)) unlink(tl); // first try to remove directory entry in destination directory if such entry exists
-
- gint success = (symlink(link_target, tl) == 0);
- g_free(link_target);
-
- if (success)
- {
- ret = TRUE;
- goto end;
- }
- } // if symlink did not succeed, continue on to try a copy procedure
- orig_copy:
-
fi = fopen(sl, "rb");
if (!fi) goto end;