option is to fall back to setting a security descriptor with the SACL omitted,
then only the default inherited security descriptor, if we do not have
permission to set the desired one.
+.TP
+\fB--rpfix\fR, \fB--norpfix\fR
+Set whether to fix targets of absolute symbolic links (reparse points in Windows
+terminology) or not. When enabled (\fB--rpfix\fR), extracted absolute symbolic
+links that are marked in the WIM image as being fixed are assumed to have
+absolute targets relative to the image root, and therefore have the actual root
+of extraction prepended to their targets. The intention is that you can apply
+an image containing absolute symbolic links and still have them be valid after
+it's been applied to any location.
+
+The default behavior is \fB--rpfix\fR if any images in \fIWIMFILE\fR have been
+captured with reparse-point fixups done. Otherwise, it is \fB--norpfix\fR.
.SH NOTES
installation media to the directory "boot":
.RS
.PP
-image apply /media/windows/sources/boot.wim 1 boot
+@IMAGEX_PROGNAME@ apply /media/windows/sources/boot.wim 1 boot
.RE
.PP
Extract all images from the Windows PE image from the Windows Vista/7/8
installation media to the directory "boot", and hard link all identical files:
.RS
.PP
-image apply /media/windows8/sources/boot.wim all boot --hardlink
+@IMAGEX_PROGNAME@ apply /media/windows8/sources/boot.wim all boot --hardlink
.RE
.PP
.SS NTFS extraction mode
In the NTFS capture mode, do not capture security descriptors. This flag is
also available in the native Win32 build of wimlib.
.TP
+\fB--rpfix\fR, \fB--norpfix\fR
+Set whether to fix targets of absolute symbolic links (reparse points in Windows
+terminology) or not. When enabled (\fB--rpfix\fR), absolute symbolic links that
+point inside the directory tree being captured will be adjusted to be absolute
+relative to the root of the directory tree being captured. In addition,
+absolute symbolic links that point outside the directory tree being captured
+will be ignored and not be captured at all. When disabled (\fB--norpfix\fR),
+absolute symbolic links will be captured exactly as is.
+
+The default behavior for \fBimagex capture\fR is equivalent to \fB--rpfix\fR.
+The default behavior for \fBimagex append\fR will be \fB--rpfix\fR if reparse
+point fixups have previously been done on \fIWIMFILE\fR, otherwise
+\fB--norpfix\fR.
+
+Links are fixed up on a per-source basis in the case of a multi-source capture
+(\fB--source-list\fR specified), so you may wish to set \fB--norpfix\fR in that
+case.
+.TP
\fB--strict-acls\fR
In the Win32 native build of wimlib, fail immediately if the full security
descriptor of any file or directory cannot be read. The default behavior
if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == 0)
- if (w->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+ {
+ /* Do reparse-point fixups by default if the header flag is set
+ * from previous images, or if this is the first image being
+ * added. */
+ if ((w->hdr.flags & WIM_HDR_FLAG_RP_FIX) || w->hdr.image_count == 0)
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+ }
if (!name || !*name) {
ERROR("Must specify a non-empty string for the image name");
inode_is_symlink(const struct wim_inode *inode)
{
return (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
- && ((inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK) ||
- inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT);
+ && (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
+ inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT);
}
static inline bool
if (export_flags & WIMLIB_EXPORT_FLAG_BOOT)
dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
+ if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+ {
+ /* Set the reparse point fixup flag on the destination WIM if
+ * the flag is set on the source WIM. */
+ dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
+ }
ret = 0;
goto out;
out_xml_delete_image:
ret = 0;
else
ret = fd_apply_unix_data(out_fd, &unix_data);
- if (ret != 0)
+ if (ret)
goto out;
}
if (lte)
if (target[args->target_realpath_len] == '/' &&
args->extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX)
{
+ /* Fix absolute symbolic link target to point into the actual
+ * extraction destination */
memcpy(target, args->target_realpath,
args->target_realpath_len);
fixed_target = target;
} else {
+ /* Keep same link target */
fixed_target = target + args->target_realpath_len;
}
ret = symlink(fixed_target, output_path);
}
#ifndef __WIN32__
-static int unix_do_apply_dentry(const char *output_path,
- size_t output_path_len,
- struct wim_dentry *dentry,
- struct apply_args *args)
+static int
+unix_do_apply_dentry(const char *output_path, size_t output_path_len,
+ struct wim_dentry *dentry, struct apply_args *args)
{
const struct wim_inode *inode = dentry->d_inode;
apply_dentry_normal(struct wim_dentry *dentry, void *arg)
{
struct apply_args *args = arg;
- tchar *output_path;
size_t len;
+ tchar *output_path;
len = tstrlen(args->target);
if (dentry_is_root(dentry)) {
output_path[len] = T('\0');
}
-
#ifdef __WIN32__
return win32_do_apply_dentry_timestamps(output_path, len, dentry, args);
#else
list_add_tail(&inode->i_lte_inode_list, <e->inode_list);
inode_added = true;
}
-#ifdef WITH_NTFS_3G
- if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+
+ /* Determine whether to include alternate data stream entries or not.
+ *
+ * UNIX: Include them if extracting using NTFS-3g.
+ *
+ * Windows: Include them undconditionally, although if the filesystem is
+ * not NTFS we won't actually be able to extract them. */
+#if defined(WITH_NTFS_3G)
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS)
+#elif defined(__WIN32__)
+ if (1)
+#else
+ if (0)
+#endif
+ {
for (unsigned i = 0; i < inode->i_num_ads; i++) {
if (inode->i_ads_entries[i].stream_name_nbytes != 0) {
lte = inode->i_ads_entries[i].lte;
}
}
}
-#endif
}
static void
/* Extract the dentry if it was not already
* extracted */
ret = maybe_apply_dentry(dentry, args);
- if (ret != 0)
+ if (ret)
return ret;
if (progress_func &&
args->progress.extract.completed_bytes >= next_progress)
return -errno;
if (!inode_is_symlink(inode))
return -EINVAL;
-
- ret = inode_readlink(inode, buf, buf_len, ctx->wim, true);
- if (ret > 0)
+ if (buf_len == 0)
+ return -ENAMETOOLONG;
+ ret = inode_readlink(inode, buf, buf_len - 1, ctx->wim, true);
+ if (ret >= 0) {
+ wimlib_assert(ret <= buf_len - 1);
+ buf[ret] = '\0';
ret = 0;
+ } else if (ret == -ENAMETOOLONG) {
+ buf[buf_len - 1] = '\0';
+ }
return ret;
}
#include <sys/stat.h>
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
/*
* Find the symlink target of a symbolic link or junction point in the WIM.
*
header_size = 12;
p += 4;
}
- if (header_size + substitute_name_offset + substitute_name_len > resource_len)
+ if (header_size +
+ substitute_name_offset + substitute_name_len > resource_len)
return -EIO;
ret = utf16le_to_tstr((const utf16lechar*)(p + substitute_name_offset),
if (ret)
return -errno;
- if (link_target_len + 1 > buf_len) {
- ret = -ENAMETOOLONG;
- goto out;
- }
-
DEBUG("Interpeting substitute name \"%s\" (ReparseTag=0x%x)",
link_target, reparse_tag);
translate_slashes = true;
/* "Relative" symlink, without drive letter */
;
} else {
- ERROR("Invalid reparse point: \"%s\"", translated_target);
+ ERROR("Invalid reparse point substitute name: \"%s\"", translated_target);
ret = -EIO;
goto out;
}
for (size_t i = 0; i < link_target_len; i++)
if (translated_target[i] == '\\')
translated_target[i] = '/';
- memcpy(buf, translated_target, link_target_len + 1);
- ret = link_target_len;
+
+ if (link_target_len > buf_len) {
+ link_target_len = buf_len;
+ ret = -ENAMETOOLONG;
+ } else {
+ ret = link_target_len;
+ }
+ memcpy(buf, translated_target, link_target_len);
out:
FREE(link_target);
return ret;
{
const struct wim_lookup_table_entry *lte;
int ret;
+ u8 *res_buf;
wimlib_assert(inode_is_symlink(inode));
if (wim_resource_size(lte) > REPARSE_POINT_MAX_SIZE)
return -EIO;
- u8 res_buf[wim_resource_size(lte)];
+ res_buf = alloca(wim_resource_size(lte));
ret = read_full_resource_into_buf(lte, res_buf, threadsafe);
if (ret)
return -EIO;
- return get_symlink_name(res_buf, wim_resource_size(lte), buf,
- buf_len, inode->i_reparse_tag);
+ return get_symlink_name(res_buf, wim_resource_size(lte),
+ buf, buf_len, inode->i_reparse_tag);
}
/*
# define os_get_ino_and_dev unix_get_ino_and_dev
#endif
-/* Fix up reparse points--- mostly shared between UNIX and Windows */
+/* Fix up absolute symbolic link targets--- mostly shared between UNIX and
+ * Windows */
tchar *
fixup_symlink(tchar *dest, u64 capture_root_ino, u64 capture_root_dev)
{
ret = os_get_ino_and_dev(dest, &ino, &dev);
*p = save;
+ if (ret) /* stat() failed before we got to the capture root---
+ assume the link points outside it. */
+ return NULL;
+
if (ino == capture_root_ino && dev == capture_root_dev) {
/* Link points inside capture root. Return abbreviated
* path. */
* current root; also exclude absolute symbolic links that point outside the
* directory tree being captured.
*
- * Without this flag, the default is to do this only if WIM_HDR_FLAG_RP_FIX is
- * set in the WIM header. WIM_HDR_FLAG_RP_FIX is set if the first image in a
- * WIM is captured with WIMLIB_ADD_IMAGE_FLAG_RPFIX enabled and currently cannot
- * be changed. */
+ * Without this flag, the default is to do this if WIM_HDR_FLAG_RP_FIX is set in
+ * the WIM header or if this is the first image being added.
+ * WIM_HDR_FLAG_RP_FIX is set if the first image in a WIM is captured with
+ * reparse point fixups enabled and currently cannot be unset. */
#define WIMLIB_ADD_IMAGE_FLAG_RPFIX 0x00000100
-/* Don't do reparse point fixups. Without this flag, the default is to do
- * reparse point fixes if WIM_HDR_FLAG_RP_FIX is set in the WIM header. */
+/* Don't do reparse point fixups. The default behavior is described in the
+ * documentation for ::WIMLIB_ADD_IMAGE_FLAG_RPFIX. */
#define WIMLIB_ADD_IMAGE_FLAG_NORPFIX 0x00000200
/******************************
#define WIMLIB_EXTRACT_FLAG_STRICT_ACLS 0x00000080
/* Extract equivalent to ::WIMLIB_ADD_IMAGE_FLAG_RPFIX; force reparse-point
- * fixups on, so absolute symbolic links are junction points will be fixed to be
+ * fixups on, so absolute symbolic links or junction points will be fixed to be
* absolute relative to the actual extraction root. Done by default if
* WIM_HDR_FLAG_RP_FIX is set in the WIM header. */
#define WIMLIB_EXTRACT_FLAG_RPFIX 0x00000100
if [ -x /usr/bin/tree -a "$ctype" = "None" ]; then
tree in.dir --inodes -F -s --noreport
fi
- if ! imagex capture in.dir test.wim --compress=$ctype; then
+ if ! imagex capture in.dir test.wim --compress=$ctype --norpfix; then
error "Failed to capture directory tree into a WIM"
fi
if ! imagex apply test.wim 1 out.dir; then
echo 'testing' > dir2/file
dd if=/dev/zero of=dir2/zeroes bs=4096 count=5
mkdir tmp.empty tmp.mnt tmp.apply tmp.orig
- imagex capture tmp.empty empty.wim
+ imagex capture tmp.empty empty.wim --norpfix
}
cleanup