From: Eric Biggers Date: Thu, 25 Apr 2013 00:42:39 +0000 (-0500) Subject: Fixes; write --{no,}rpfix docs; enable --rpfix capture by default X-Git-Tag: v1.3.3~49 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=df7f6ca9f3d34b5133667ad35f800b7afcabe434 Fixes; write --{no,}rpfix docs; enable --rpfix capture by default --- diff --git a/doc/imagex-apply.1.in b/doc/imagex-apply.1.in index b59a5930..5db59f92 100644 --- a/doc/imagex-apply.1.in +++ b/doc/imagex-apply.1.in @@ -263,6 +263,18 @@ be set exactly as specified in the WIM file. The default behavior without this 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 @@ -286,14 +298,14 @@ Extract the first image from the Windows PE image from the Windows Vista/7/8 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 diff --git a/doc/imagex-capture.1.in b/doc/imagex-capture.1.in index e20e0979..05c43fda 100644 --- a/doc/imagex-capture.1.in +++ b/doc/imagex-capture.1.in @@ -237,6 +237,24 @@ information. 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 diff --git a/src/add_image.c b/src/add_image.c index 8e97a8ec..b50b05b5 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -865,8 +865,13 @@ wimlib_add_image_multisource(WIMStruct *w, 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"); diff --git a/src/dentry.h b/src/dentry.h index 5c57e7e9..5e42e91f 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -508,8 +508,8 @@ static inline bool 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 diff --git a/src/export_image.c b/src/export_image.c index 34564e22..c5c85d5f 100644 --- a/src/export_image.c +++ b/src/export_image.c @@ -252,6 +252,12 @@ wimlib_export_image(WIMStruct *src_wim, 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: diff --git a/src/extract_image.c b/src/extract_image.c index 48a916ab..aae779e9 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -281,7 +281,7 @@ out_extract_unix_data: ret = 0; else ret = fd_apply_unix_data(out_fd, &unix_data); - if (ret != 0) + if (ret) goto out; } if (lte) @@ -342,10 +342,13 @@ extract_symlink(struct wim_dentry *dentry, 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); @@ -421,10 +424,9 @@ dir_exists: } #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; @@ -504,8 +506,8 @@ static int 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)) { @@ -546,7 +548,6 @@ apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg) output_path[len] = T('\0'); } - #ifdef __WIN32__ return win32_do_apply_dentry_timestamps(output_path, len, dentry, args); #else @@ -637,8 +638,21 @@ inode_find_streams_for_extraction(struct wim_inode *inode, 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; @@ -654,7 +668,6 @@ inode_find_streams_for_extraction(struct wim_inode *inode, } } } -#endif } static void @@ -725,7 +738,7 @@ apply_stream_list(struct list_head *stream_list, /* 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) diff --git a/src/mount_image.c b/src/mount_image.c index 78562019..b00a2a68 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -2024,10 +2024,16 @@ wimfs_readlink(const char *path, char *buf, size_t buf_len) 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; } diff --git a/src/symlink.c b/src/symlink.c index 587b71cb..ea92a2df 100644 --- a/src/symlink.c +++ b/src/symlink.c @@ -34,6 +34,10 @@ #include +#ifdef HAVE_ALLOCA_H +# include +#endif + /* * Find the symlink target of a symbolic link or junction point in the WIM. * @@ -77,7 +81,8 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf, 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), @@ -86,11 +91,6 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf, 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; @@ -133,7 +133,7 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf, /* "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; } @@ -142,8 +142,14 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf, 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; @@ -291,6 +297,7 @@ inode_readlink(const struct wim_inode *inode, char *buf, size_t buf_len, { const struct wim_lookup_table_entry *lte; int ret; + u8 *res_buf; wimlib_assert(inode_is_symlink(inode)); @@ -301,12 +308,12 @@ inode_readlink(const struct wim_inode *inode, char *buf, size_t buf_len, 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); } /* @@ -406,7 +413,8 @@ unix_get_ino_and_dev(const char *path, u64 *ino_ret, u64 *dev_ret) # 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) { @@ -433,6 +441,10 @@ 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. */ diff --git a/src/wimlib.h b/src/wimlib.h index e7f89faa..ed036e7b 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -700,14 +700,14 @@ struct wimlib_capture_config { * 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 /****************************** @@ -758,7 +758,7 @@ struct wimlib_capture_config { #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 diff --git a/tests/test-imagex-capture_and_apply b/tests/test-imagex-capture_and_apply index dfa240f8..ce54c74a 100755 --- a/tests/test-imagex-capture_and_apply +++ b/tests/test-imagex-capture_and_apply @@ -39,7 +39,7 @@ do_test() { 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 diff --git a/tests/test-imagex-mount b/tests/test-imagex-mount index 906a3d65..d7c75e16 100755 --- a/tests/test-imagex-mount +++ b/tests/test-imagex-mount @@ -36,7 +36,7 @@ init() { 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