]> wimlib.net Git - wimlib/commitdiff
Fixes; write --{no,}rpfix docs; enable --rpfix capture by default
authorEric Biggers <ebiggers3@gmail.com>
Thu, 25 Apr 2013 00:42:39 +0000 (19:42 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 25 Apr 2013 00:42:39 +0000 (19:42 -0500)
doc/imagex-apply.1.in
doc/imagex-capture.1.in
src/add_image.c
src/dentry.h
src/export_image.c
src/extract_image.c
src/mount_image.c
src/symlink.c
src/wimlib.h
tests/test-imagex-capture_and_apply
tests/test-imagex-mount

index b59a5930922eb215314bc7ba710646a64035eefc..5db59f92a7f0fd0ac91fb559aacef08c14a54d7f 100644 (file)
@@ -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.
 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
 
 
 .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
 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
 .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
 .RE
 .PP
 .SS NTFS extraction mode
index e20e0979d7385ad2ec4596dd37e86e19e3ebd66a..05c43fdaa756020c5821b79d317a5bf66f1e787e 100644 (file)
@@ -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
 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
 \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
index 8e97a8ec1e95c3b7e623dba8e5b174880fb913a9..b50b05b55400c6c01fe6d0dac616118abd73ce4a 100644 (file)
@@ -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 ((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;
                        add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+       }
 
        if (!name || !*name) {
                ERROR("Must specify a non-empty string for the image name");
 
        if (!name || !*name) {
                ERROR("Must specify a non-empty string for the image name");
index 5c57e7e9178ece9f0392038fcc2524b34d463e8e..5e42e91f7c39c0909b39e0d8c63b587f4b4a99f0 100644 (file)
@@ -508,8 +508,8 @@ static inline bool
 inode_is_symlink(const struct wim_inode *inode)
 {
        return (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
 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
 }
 
 static inline bool
index 34564e222e2cd70b1748008fbbb1eaf8fd85c8f4..c5c85d5f77f401070693ed42f8016c6e0b37b162 100644 (file)
@@ -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 (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;
        goto out;
 out_xml_delete_image:
index 48a916ab5517652e4a2663c42446f983f7cd111e..aae779e9bf2f1450f239042b06eb29eb20d9ee7a 100644 (file)
@@ -281,7 +281,7 @@ out_extract_unix_data:
                        ret = 0;
                else
                        ret = fd_apply_unix_data(out_fd, &unix_data);
                        ret = 0;
                else
                        ret = fd_apply_unix_data(out_fd, &unix_data);
-               if (ret != 0)
+               if (ret)
                        goto out;
        }
        if (lte)
                        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)
        {
        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 {
                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);
                fixed_target = target + args->target_realpath_len;
        }
        ret = symlink(fixed_target, output_path);
@@ -421,10 +424,9 @@ dir_exists:
 }
 
 #ifndef __WIN32__
 }
 
 #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;
 
 {
        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;
 apply_dentry_normal(struct wim_dentry *dentry, void *arg)
 {
        struct apply_args *args = arg;
-       tchar *output_path;
        size_t len;
        size_t len;
+       tchar *output_path;
 
        len = tstrlen(args->target);
        if (dentry_is_root(dentry)) {
 
        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');
        }
 
                output_path[len] = T('\0');
        }
 
-
 #ifdef __WIN32__
        return win32_do_apply_dentry_timestamps(output_path, len, dentry, args);
 #else
 #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, &lte->inode_list);
                inode_added = true;
        }
                list_add_tail(&inode->i_lte_inode_list, &lte->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;
                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
 }
 
 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);
                                /* 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 ret;
                                if (progress_func &&
                                    args->progress.extract.completed_bytes >= next_progress)
index 785620197c857492f30cf83b1c63e4af15e2a178..b00a2a686c28bcb7cebb67f97f4d18d562bb8187 100644 (file)
@@ -2024,10 +2024,16 @@ wimfs_readlink(const char *path, char *buf, size_t buf_len)
                return -errno;
        if (!inode_is_symlink(inode))
                return -EINVAL;
                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;
                ret = 0;
+       } else if (ret == -ENAMETOOLONG) {
+               buf[buf_len - 1] = '\0';
+       }
        return ret;
 }
 
        return ret;
 }
 
index 587b71cb8f07f5c31b802b53df1cdda71c398ff7..ea92a2df40f76253ef5367ae202906c2a44b9040 100644 (file)
 
 #include <sys/stat.h>
 
 
 #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.
  *
 /*
  * 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;
        }
                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),
                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 (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;
        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 {
                        /* "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;
        }
                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] = '/';
                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;
 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;
 {
        const struct wim_lookup_table_entry *lte;
        int ret;
+       u8 *res_buf;
 
        wimlib_assert(inode_is_symlink(inode));
 
 
        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;
 
        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;
        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
 
 #  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)
 {
 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;
 
                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. */
                if (ino == capture_root_ino && dev == capture_root_dev) {
                        /* Link points inside capture root.  Return abbreviated
                         * path. */
index e7f89faa4ab3eb5ed18d6928dd89621ec67863ba..ed036e7bad51d8f5d3f57442345e2ca2781d9d18 100644 (file)
@@ -700,14 +700,14 @@ struct wimlib_capture_config {
  * current root; also exclude absolute symbolic links that point outside the
  * directory tree being captured.
  *
  * 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
 
 #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_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
 #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
  * 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
index dfa240f819be3fb2bd96e583a575f092bd0292b1..ce54c74acb12748da84b364c6bfe0b0d7e680387 100755 (executable)
@@ -39,7 +39,7 @@ do_test() {
                if [ -x /usr/bin/tree -a "$ctype" = "None" ]; then
                        tree in.dir --inodes -F -s --noreport
                fi
                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
                        error "Failed to capture directory tree into a WIM"
                fi
                if ! imagex apply test.wim 1 out.dir; then
index 906a3d65c76e0cc0e40ce0518bef7613a1f85f12..d7c75e1670d8edba38b8afb2367531f49c5eee1f 100755 (executable)
@@ -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
        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
 }
 
 cleanup