+static int
+unix_get_ino_and_dev(const char *path, u64 *ino_ret, u64 *dev_ret)
+{
+ struct stat stbuf;
+ if (stat(path, &stbuf)) {
+ WARNING_WITH_ERRNO("Failed to stat \"%s\"", path);
+ /* Treat as a link pointing outside the capture root (it
+ * most likely is). */
+ return WIMLIB_ERR_STAT;
+ } else {
+ *ino_ret = stbuf.st_ino;
+ *dev_ret = stbuf.st_dev;
+ return 0;
+ }
+}
+
+#endif /* !defined(__WIN32__) */
+
+#ifdef __WIN32__
+# include "win32.h"
+# define RP_PATH_SEPARATOR L'\\'
+# define os_get_ino_and_dev win32_get_file_and_vol_ids
+#else
+# define RP_PATH_SEPARATOR '/'
+# define os_get_ino_and_dev unix_get_ino_and_dev
+#endif
+
+/* Fix up reparse points--- mostly shared between UNIX and Windows */
+tchar *
+fixup_symlink(tchar *dest, u64 capture_root_ino, u64 capture_root_dev)
+{
+ tchar *p = dest;
+
+#ifdef __WIN32__
+ /* Skip over drive letter */
+ if (*p != RP_PATH_SEPARATOR)
+ p += 2;
+#endif
+
+ DEBUG("Fixing symlink or junction \"%"TS"\"", dest);
+ for (;;) {
+ tchar save;
+ int ret;
+ u64 ino;
+ u64 dev;
+
+ while (*p == RP_PATH_SEPARATOR)
+ p++;
+
+ save = *p;
+ *p = T('\0');
+ ret = os_get_ino_and_dev(dest, &ino, &dev);
+ *p = save;
+
+ if (ino == capture_root_ino && dev == capture_root_dev) {
+ /* Link points inside capture root. Return abbreviated
+ * path. */
+ if (*p == T('\0'))
+ *(p - 1) = RP_PATH_SEPARATOR;
+ while (p - 1 >= dest && *(p - 1) == RP_PATH_SEPARATOR)
+ p--;
+ #ifdef __WIN32__
+ /* Add back drive letter */
+ if (*dest != RP_PATH_SEPARATOR) {
+ *--p = *(dest + 1);
+ *--p = *dest;
+ }
+ #endif
+ wimlib_assert(p >= dest);
+ return p;
+ }
+
+ if (*p == T('\0')) {
+ /* Link points outside capture root. */
+ return NULL;
+ }
+
+ do {
+ p++;
+ } while (*p != RP_PATH_SEPARATOR && *p != T('\0'));
+ }
+}
+