+
+ /*
+ * Don't do reparse point fixups on relative symbolic links.
+ *
+ * On Windows, a relative symbolic link is supposed to be identifiable
+ * by having reparse tag WIM_IO_REPARSE_TAG_SYMLINK and flags
+ * SYMBOLIC_LINK_RELATIVE. We will use this information, although this
+ * may not always do what the user expects, since drive-relative
+ * symbolic links such as "\Users\Public" have SYMBOLIC_LINK_RELATIVE
+ * set, in addition to truely relative symbolic links such as "Users" or
+ * "Users\Public". However, WIMGAPI (as of Windows 8.1) has this same
+ * behavior.
+ *
+ * Otherwise, as far as I can tell, the targets of symbolic links that
+ * are NOT relative, as well as junctions (note: a mountpoint is the
+ * sames thing as a junction), must be NT namespace paths, for example:
+ *
+ * - \??\e:\Users\Public
+ * - \DosDevices\e:\Users\Public
+ * - \Device\HardDiskVolume4\Users\Public
+ * - \??\Volume{c47cb07c-946e-4155-b8f7-052e9cec7628}\Users\Public
+ * - \DosDevices\Volume{c47cb07c-946e-4155-b8f7-052e9cec7628}\Users\Public
+ */
+ if (rpdata.rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
+ (rpdata.rpflags & SYMBOLIC_LINK_RELATIVE))
+ return RP_NOT_FIXED;
+
+ rel_target = winnt_get_root_relative_target(rpdata.substitute_name,
+ rpdata.substitute_name_nbytes,
+ capture_root_ino,
+ capture_root_dev);
+ if (!rel_target) {
+ /* Target points outside of the tree being captured. Exclude
+ * this reparse point from the capture (but inform the library
+ * user). */
+ size_t print_name_nchars = rpdata.print_name_nbytes / sizeof(wchar_t);
+ wchar_t print_name0[print_name_nchars + 1];
+ print_name0[print_name_nchars] = L'\0';
+ wmemcpy(print_name0, rpdata.print_name, print_name_nchars);
+
+ params->progress.scan.cur_path = printable_path(path);
+ params->progress.scan.symlink_target = print_name0;
+ int ret = do_capture_progress(params,
+ WIMLIB_SCAN_DENTRY_EXCLUDED_SYMLINK,
+ NULL);
+ if (ret)
+ return ret;
+ return RP_EXCLUDED;
+ }
+
+ if (rel_target == rpdata.substitute_name) {
+ /* Weird target --- keep the reparse point and don't mess with
+ * it. */
+ return RP_NOT_FIXED;
+ }
+
+ /* We have an absolute target pointing within the directory being
+ * captured, @rel_target is the suffix of the link target that is the
+ * part relative to the directory being captured.
+ *
+ * We will cut off the prefix before this part (which is the path to the
+ * directory being captured) and add a dummy prefix. Since the process
+ * will need to be reversed when applying the image, it shouldn't matter
+ * what exactly the prefix is, as long as it looks like an absolute
+ * path.
+ */
+
+ {
+ size_t rel_target_nbytes =
+ rpdata.substitute_name_nbytes - ((const u8 *)rel_target -
+ (const u8 *)rpdata.substitute_name);
+ size_t rel_target_nchars = rel_target_nbytes / sizeof(wchar_t);
+
+ wchar_t tmp[rel_target_nchars + 7];
+
+ wmemcpy(tmp, L"\\??\\X:\\", 7);
+ wmemcpy(tmp + 7, rel_target, rel_target_nchars);
+
+ rpdata.substitute_name = tmp;
+ rpdata.substitute_name_nbytes = rel_target_nbytes + (7 * sizeof(wchar_t));
+ rpdata.print_name = tmp + 4;
+ rpdata.print_name_nbytes = rel_target_nbytes + (3 * sizeof(wchar_t));
+
+ if (make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p))
+ return RP_NOT_FIXED;
+ }
+ return RP_FIXED;