+ if (unlikely(ret >= sizeof(orig_target))) {
+ ERROR("\"%s\": target of symbolic link is too long", full_path);
+ return WIMLIB_ERR_READLINK;
+ }
+ target[ret] = '\0';
+
+ /* If the link is absolute and reparse point fixups are enabled, then
+ * change it to be "absolute" relative to the tree being captured. */
+ if (target[0] == '/' && (params->add_flags & WIMLIB_ADD_FLAG_RPFIX)) {
+ int status = WIMLIB_SCAN_DENTRY_NOT_FIXED_SYMLINK;
+
+ params->progress.scan.cur_path = full_path;
+ params->progress.scan.symlink_target = target;
+
+ target = unix_relativize_link_target(target,
+ params->capture_root_ino,
+ params->capture_root_dev);
+ if (target != orig_target) {
+ /* Link target was fixed. */
+ inode->i_rp_flags &= ~WIM_RP_FLAG_NOT_FIXED;
+ status = WIMLIB_SCAN_DENTRY_FIXED_SYMLINK;
+ }
+ ret = do_scan_progress(params, status, NULL);
+ if (ret)
+ return ret;
+ }
+
+ /* Translate the UNIX symlink target into a Windows reparse point. */
+ ret = wim_inode_set_symlink(inode, target, params->blob_table);
+ if (unlikely(ret)) {
+ if (ret == WIMLIB_ERR_INVALID_UTF8_STRING) {
+ ERROR("\"%s\": target of symbolic link is not valid "
+ "UTF-8. This is not supported.", full_path);
+ }
+ return ret;
+ }
+
+ /* On Windows, a reparse point can be set on both directory and
+ * non-directory files. Usually, a link that is intended to point to a
+ * (non-)directory is stored as a reparse point on a (non-)directory
+ * file. Replicate this behavior by examining the target file. */
+ struct stat stbuf;
+ if (my_fstatat(full_path, dirfd, relpath, &stbuf, 0) == 0 &&
+ S_ISDIR(stbuf.st_mode))
+ inode->i_attributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return 0;