- int ret;
-
- DEBUG("Creating hardlink \"%"TS"\" => \"%"TS"\"", newpath, oldpath);
- ret = ctx->ops->create_hardlink(oldpath, newpath, ctx);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create hardlink "
- "\"%"TS"\" => \"%"TS"\"",
- newpath, oldpath);
- }
- return ret;
-}
-
-#ifdef __WIN32__
-static int
-try_extract_rpfix(u8 *rpbuf,
- u16 *rpbuflen_p,
- const wchar_t *extract_root_realpath,
- unsigned extract_root_realpath_nchars)
-{
- struct reparse_data rpdata;
- wchar_t *target;
- size_t target_nchars;
- size_t stripped_nchars;
- wchar_t *stripped_target;
- wchar_t stripped_target_nchars;
- int ret;
-
- utf16lechar *new_target;
- utf16lechar *new_print_name;
- size_t new_target_nchars;
- size_t new_print_name_nchars;
- utf16lechar *p;
-
- ret = parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata);
- if (ret)
- return ret;
-
- if (extract_root_realpath[0] == L'\0' ||
- extract_root_realpath[1] != L':' ||
- extract_root_realpath[2] != L'\\')
- return WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED;
-
- ret = parse_substitute_name(rpdata.substitute_name,
- rpdata.substitute_name_nbytes,
- rpdata.rptag);
- if (ret < 0)
- return 0;
- stripped_nchars = ret;
- target = rpdata.substitute_name;
- target_nchars = rpdata.substitute_name_nbytes / sizeof(utf16lechar);
- stripped_target = target + stripped_nchars;
- stripped_target_nchars = target_nchars - stripped_nchars;
-
- new_target = alloca((6 + extract_root_realpath_nchars +
- stripped_target_nchars) * sizeof(utf16lechar));
-
- p = new_target;
- if (stripped_nchars == 6) {
- /* Include \??\ prefix if it was present before */
- p = wmempcpy(p, L"\\??\\", 4);
- }
-
- /* Print name excludes the \??\ if present. */
- new_print_name = p;
- if (stripped_nchars != 0) {
- /* Get drive letter from real path to extract root, if a drive
- * letter was present before. */
- *p++ = extract_root_realpath[0];
- *p++ = extract_root_realpath[1];
- }
- /* Copy the rest of the extract root */
- p = wmempcpy(p, extract_root_realpath + 2, extract_root_realpath_nchars - 2);
-
- /* Append the stripped target */
- p = wmempcpy(p, stripped_target, stripped_target_nchars);
- new_target_nchars = p - new_target;
- new_print_name_nchars = p - new_print_name;
-
- if (new_target_nchars * sizeof(utf16lechar) >= REPARSE_POINT_MAX_SIZE ||
- new_print_name_nchars * sizeof(utf16lechar) >= REPARSE_POINT_MAX_SIZE)
- return WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED;
-
- rpdata.substitute_name = new_target;
- rpdata.substitute_name_nbytes = new_target_nchars * sizeof(utf16lechar);
- rpdata.print_name = new_print_name;
- rpdata.print_name_nbytes = new_print_name_nchars * sizeof(utf16lechar);
- return make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p);
-}
-#endif /* __WIN32__ */
-
-/* Set reparse data on extracted file or directory that has
- * FILE_ATTRIBUTE_REPARSE_POINT set. */
-static int
-extract_reparse_data(const tchar *path, struct apply_ctx *ctx,
- struct wim_inode *inode,
- struct wim_lookup_table_entry *lte_override)
-{
- int ret;
- u8 rpbuf[REPARSE_POINT_MAX_SIZE];
- u16 rpbuflen;
-
- ret = wim_inode_get_reparse_data(inode, rpbuf, &rpbuflen, lte_override);
- if (ret)
- goto error;
-
-#ifdef __WIN32__
- /* Fix up target of absolute symbolic link or junction points so
- * that they point into the actual extraction target. */
- if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX) &&
- (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
- inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT) &&
- !inode->i_not_rpfixed)
- {
- ret = try_extract_rpfix(rpbuf, &rpbuflen, ctx->realtarget,
- ctx->realtarget_nchars);
- if (ret && !(ctx->extract_flags &
- WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS))
- {
- WARNING("Reparse point fixup of \"%"TS"\" "
- "failed", path);
- ret = 0;
- }
- if (ret)
- goto error;
- }
-#endif
-
- ret = ctx->ops->set_reparse_data(path, rpbuf, rpbuflen, ctx);
-
- /* On Windows, the SeCreateSymbolicLink privilege is required to create
- * symbolic links. To be more friendly towards non-Administrator users,
- * we merely warn the user if symbolic links cannot be created due to
- * insufficient permissions or privileges, unless
- * WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS was provided. */
-#ifdef __WIN32__
- if (ret && inode_is_symlink(inode) &&
- (errno == EACCES || errno == EPERM) &&
- !(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS))
- {
- WARNING("Can't set reparse data on \"%"TS"\": "
- "Access denied!\n"
- " You may be trying to "
- "extract a symbolic link without the\n"
- " SeCreateSymbolicLink privilege, "
- "which by default non-Administrator\n"
- " accounts do not have.",
- path);
- ret = 0;
- }
-#endif
- if (ret)
- goto error;
-
- /* Account for reparse data consumed. */
- update_extract_progress(ctx,
- (lte_override ? lte_override :
- inode_unnamed_lte_resolved(inode)));
- return 0;
-
-error:
- ERROR_WITH_ERRNO("Failed to set reparse data on \"%"TS"\"", path);
- return ret;