]> wimlib.net Git - wimlib/commitdiff
Windows rpfix capture (in progress)
authorEric Biggers <ebiggers3@gmail.com>
Mon, 22 Apr 2013 05:58:45 +0000 (00:58 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 22 Apr 2013 05:58:45 +0000 (00:58 -0500)
src/add_image.c
src/dentry.c
src/dentry.h
src/symlink.c
src/wimlib_internal.h
src/win32.c
src/win32.h

index e45bc1c1449b9efd72f51a7aa3cae7db4131b060..8e97a8ec1e95c3b7e623dba8e5b174880fb913a9 100644 (file)
@@ -179,53 +179,6 @@ unix_capture_directory(struct wim_dentry *dir_dentry,
        return ret;
 }
 
        return ret;
 }
 
-static char *
-fixup_symlink(char *dest, ino_t capture_root_ino, dev_t capture_root_dev)
-{
-       char *p = dest;
-       struct stat stbuf;
-
-       for (;;) {
-               char save;
-               int ret;
-
-               while (*p == '/')
-                       p++;
-
-               save = *p;
-               *p = '\0';
-               if (stat(dest, &stbuf)) {
-                       WARNING_WITH_ERRNO("Failed to stat \"%s\": %m", dest);
-                       *p = save;
-                       /* Treat as a link pointing outside the capture root (it
-                        * most likely is). */
-                       return NULL;
-               }
-               *p = save;
-
-               if (stbuf.st_ino == capture_root_ino &&
-                   stbuf.st_dev == capture_root_dev)
-               {
-                       /* Link points inside capture root.  Return abbreviated
-                        * path. */
-                       if (*p == '\0')
-                               *(p - 1) = '/';
-                       while (p - 1 >= dest && *(p - 1) == '/')
-                               p--;
-                       return p;
-               }
-
-               if (*p == '\0') {
-                       /* Link points outside capture root. */
-                       return NULL;
-               }
-
-               do {
-                       p++;
-               } while (*p != '/' && *p != '\0');
-       }
-}
-
 static int
 unix_capture_symlink(struct wim_dentry **root_p,
                     const char *path,
 static int
 unix_capture_symlink(struct wim_dentry **root_p,
                     const char *path,
@@ -269,6 +222,7 @@ unix_capture_symlink(struct wim_dentry **root_p,
                                *root_p = NULL;
                                return 0;
                        }
                                *root_p = NULL;
                                return 0;
                        }
+                       inode->i_not_rpfixed = 0;
                }
                ret = inode_set_symlink(inode, dest,
                                        params->lookup_table, NULL);
                }
                ret = inode_set_symlink(inode, dest,
                                        params->lookup_table, NULL);
index 5b19f6f51af2ac59a4c63cff51e61c950c13c3ee..99fb24261c3fe2b2837b712a3e0496baa6a19e23 100644 (file)
@@ -702,6 +702,7 @@ new_timeless_inode()
                inode->i_security_id = -1;
                inode->i_nlink = 1;
                inode->i_next_stream_id = 1;
                inode->i_security_id = -1;
                inode->i_nlink = 1;
                inode->i_next_stream_id = 1;
+               inode->i_not_rpfixed = 1;
        #ifdef WITH_FUSE
                if (pthread_mutex_init(&inode->i_mutex, NULL) != 0) {
                        ERROR_WITH_ERRNO("Error initializing mutex");
        #ifdef WITH_FUSE
                if (pthread_mutex_init(&inode->i_mutex, NULL) != 0) {
                        ERROR_WITH_ERRNO("Error initializing mutex");
@@ -1217,8 +1218,9 @@ replace_forbidden_characters(utf16lechar *name)
        #ifdef __WIN32__
                if (wcschr(L"<>:\"/\\|?*", (wchar_t)*p))
        #else
        #ifdef __WIN32__
                if (wcschr(L"<>:\"/\\|?*", (wchar_t)*p))
        #else
-               if (*p == '/') {
+               if (*p == '/')
        #endif
        #endif
+               {
                        if (name) {
                                WARNING("File, directory, or stream name \"%"WS"\"\n"
                                        "          contains forbidden characters; "
                        if (name) {
                                WARNING("File, directory, or stream name \"%"WS"\"\n"
                                        "          contains forbidden characters; "
@@ -1482,7 +1484,8 @@ read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
                p += 4;
                p = get_u32(p, &inode->i_reparse_tag);
        if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
                p += 4;
                p = get_u32(p, &inode->i_reparse_tag);
-               p += 4;
+               p += 2;
+               p = get_u16(p, &inode->i_not_rpfixed);
        } else {
                p += 4;
                /* i_reparse_tag is irrelevant; just leave it at 0. */
        } else {
                p += 4;
                /* i_reparse_tag is irrelevant; just leave it at 0. */
@@ -1754,9 +1757,10 @@ write_dentry(const struct wim_dentry *dentry, u8 *p)
        hash = inode_stream_hash(inode, 0);
        p = put_bytes(p, SHA1_HASH_SIZE, hash);
        if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
        hash = inode_stream_hash(inode, 0);
        p = put_bytes(p, SHA1_HASH_SIZE, hash);
        if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-               p = put_zeroes(p, 4);
+               p = put_u32(p, 0);
                p = put_u32(p, inode->i_reparse_tag);
                p = put_u32(p, inode->i_reparse_tag);
-               p = put_zeroes(p, 4);
+               p = put_u16(p, 0);
+               p = put_u16(p, inode->i_not_rpfixed);
        } else {
                u64 link_group_id;
                p = put_u32(p, 0);
        } else {
                u64 link_group_id;
                p = put_u32(p, 0);
index 5d12b4b857ccccf5949f1aedf30801362f57276f..042ffe6071ae922485aae125c478243b07d1f17c 100644 (file)
@@ -231,6 +231,8 @@ struct wim_inode {
        /* Used only in NTFS-mode extraction */
        u8 i_dos_name_extracted : 1;
 
        /* Used only in NTFS-mode extraction */
        u8 i_dos_name_extracted : 1;
 
+       u16 i_not_rpfixed;
+
        /* Number of alternate data streams associated with this inode */
        u16 i_num_ads;
 
        /* Number of alternate data streams associated with this inode */
        u16 i_num_ads;
 
index dc365e8cf5787a9b335e3ac77bce214f6ac853d3..366e54ed36af853517d0d43b5eac0e53619c82c3 100644 (file)
 #include "sha1.h"
 #include <errno.h>
 
 #include "sha1.h"
 #include <errno.h>
 
-/* None of this file is ever needed in Win32 builds because the reparse point
- * buffers are not parsed. */
+/* UNIX version of getting and setting the data in reparse points */
 #if !defined(__WIN32__)
 
 #if !defined(__WIN32__)
 
+#include <sys/stat.h>
+
 /*
  * 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.
  *
@@ -54,6 +55,7 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf,
        u16 print_name_offset;
        u16 print_name_len;
        char *link_target;
        u16 print_name_offset;
        u16 print_name_len;
        char *link_target;
+       char *translated_target;
        size_t link_target_len;
        ssize_t ret;
        unsigned header_size;
        size_t link_target_len;
        ssize_t ret;
        unsigned header_size;
@@ -92,54 +94,55 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf,
        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;
+       translated_target = link_target;
        if (link_target_len >= 7 &&
        if (link_target_len >= 7 &&
-           link_target[0] == '\\' &&
-           link_target[1] == '?' &&
-           link_target[2] == '?' &&
-           link_target[3] == '\\' &&
-           link_target[4] != '\0' &&
-           link_target[5] == ':' &&
-           link_target[6] == '\\')
+           translated_target[0] == '\\' &&
+           translated_target[1] == '?' &&
+           translated_target[2] == '?' &&
+           translated_target[3] == '\\' &&
+           translated_target[4] != '\0' &&
+           translated_target[5] == ':' &&
+           translated_target[6] == '\\')
        {
                /* "Full" symlink or junction (\??\x:\ prefixed path) */
        {
                /* "Full" symlink or junction (\??\x:\ prefixed path) */
-               link_target += 6;
+               translated_target += 6;
                link_target_len -= 6;
        } else if (reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT &&
                   link_target_len >= 12 &&
                link_target_len -= 6;
        } else if (reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT &&
                   link_target_len >= 12 &&
-                  memcmp(link_target, "\\\\?\\Volume{", 11) == 0 &&
-                  link_target[link_target_len - 1] == '\\')
+                  memcmp(translated_target, "\\\\?\\Volume{", 11) == 0 &&
+                  translated_target[link_target_len - 1] == '\\')
        {
                /* Volume junction.  Can't really do anything with it. */
                translate_slashes = false;
        } else if (reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK &&
                   link_target_len >= 3 &&
        {
                /* Volume junction.  Can't really do anything with it. */
                translate_slashes = false;
        } else if (reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK &&
                   link_target_len >= 3 &&
-                  link_target[0] != '\0' &&
-                  link_target[1] == ':' &&
-                  link_target[2] == '/')
+                  translated_target[0] != '\0' &&
+                  translated_target[1] == ':' &&
+                  translated_target[2] == '/')
        {
                /* "Absolute" symlink, with drive letter */
        {
                /* "Absolute" symlink, with drive letter */
-               link_target += 2;
+               translated_target += 2;
                link_target_len -= 2;
        } else if (reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK &&
                   link_target_len >= 1)
        {
                link_target_len -= 2;
        } else if (reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK &&
                   link_target_len >= 1)
        {
-               if (link_target[0] == '/')
+               if (translated_target[0] == '/')
                        /* "Absolute" symlink, without drive letter */
                        ;
                else
                        /* "Relative" symlink, without drive letter */
                        ;
        } else {
                        /* "Absolute" symlink, without drive letter */
                        ;
                else
                        /* "Relative" symlink, without drive letter */
                        ;
        } else {
-               ERROR("Invalid reparse point: \"%s\"", link_target);
+               ERROR("Invalid reparse point: \"%s\"", translated_target);
                ret = -EIO;
                goto out;
        }
 
        if (translate_slashes)
                for (size_t i = 0; i < link_target_len; i++)
                ret = -EIO;
                goto out;
        }
 
        if (translate_slashes)
                for (size_t i = 0; i < link_target_len; i++)
-                       if (link_target[i] == '\\')
-                               link_target[i] = '/';
-       memcpy(buf, link_target, link_target_len + 1);
+                       if (translated_target[i] == '\\')
+                               translated_target[i] = '/';
+       memcpy(buf, translated_target, link_target_len + 1);
        ret = link_target_len;
 out:
        FREE(link_target);
        ret = link_target_len;
 out:
        FREE(link_target);
@@ -156,24 +159,26 @@ make_symlink_reparse_data_buf(const char *symlink_target,
 
        ret = tstr_to_utf16le(symlink_target, strlen(symlink_target),
                              &name_utf16le, &name_utf16le_nbytes);
 
        ret = tstr_to_utf16le(symlink_target, strlen(symlink_target),
                              &name_utf16le, &name_utf16le_nbytes);
-       if (ret != 0)
+       if (ret)
                return ret;
 
        for (size_t i = 0; i < name_utf16le_nbytes / 2; i++)
                if (name_utf16le[i] == cpu_to_le16('/'))
                        name_utf16le[i] = cpu_to_le16('\\');
 
                return ret;
 
        for (size_t i = 0; i < name_utf16le_nbytes / 2; i++)
                if (name_utf16le[i] == cpu_to_le16('/'))
                        name_utf16le[i] = cpu_to_le16('\\');
 
-       size_t len = 12 + name_utf16le_nbytes * 2;
+       size_t len = 12 + (name_utf16le_nbytes + 2) * 2;
        void *buf = MALLOC(len);
        if (buf) {
                void *p = buf;
        void *buf = MALLOC(len);
        if (buf) {
                void *p = buf;
-               p = put_u16(p, name_utf16le_nbytes); /* Substitute name offset */
+               p = put_u16(p, 0); /* Substitute name offset */
                p = put_u16(p, name_utf16le_nbytes); /* Substitute name length */
                p = put_u16(p, name_utf16le_nbytes); /* Substitute name length */
-               p = put_u16(p, 0); /* Print name offset */
+               p = put_u16(p, name_utf16le_nbytes + 2); /* Print name offset */
                p = put_u16(p, name_utf16le_nbytes); /* Print name length */
                p = put_u16(p, name_utf16le_nbytes); /* Print name length */
-               p = put_u32(p, 1); /* flags: 0 iff *full* target, including drive letter??? */
+               p = put_u32(p, 1); /* flags: 0 if relative link, otherwise 1 */
                p = put_bytes(p, name_utf16le_nbytes, name_utf16le);
                p = put_bytes(p, name_utf16le_nbytes, name_utf16le);
+               p = put_u16(p, 0);
                p = put_bytes(p, name_utf16le_nbytes, name_utf16le);
                p = put_bytes(p, name_utf16le_nbytes, name_utf16le);
+               p = put_u16(p, 0);
                *len_ret = len;
                *buf_ret = buf;
                ret = 0;
                *len_ret = len;
                *buf_ret = buf;
                ret = 0;
@@ -284,4 +289,86 @@ out_free_symlink_buf:
        return ret;
 }
 
        return ret;
 }
 
+static int
+unix_get_ino_and_dev(const char *path, u64 *ino_ret, u64 *dev_ret)
+{
+       struct stat stbuf;
+       if (stat(path, &stbuf)) {
+               WARNING_WITH_ERRNO("Failed to stat \"%s\"", path);
+               /* Treat as a link pointing outside the capture root (it
+                * most likely is). */
+               return WIMLIB_ERR_STAT;
+       } else {
+               *ino_ret = stbuf.st_ino;
+               *dev_ret = stbuf.st_dev;
+               return 0;
+       }
+}
+
 #endif /* !defined(__WIN32__) */
 #endif /* !defined(__WIN32__) */
+
+#ifdef __WIN32__
+#  include "win32.h"
+#  define RP_PATH_SEPARATOR L'\\'
+#  define os_get_ino_and_dev win32_get_file_and_vol_ids
+#else
+#  define RP_PATH_SEPARATOR '/'
+#  define os_get_ino_and_dev unix_get_ino_and_dev
+#endif
+
+/* Fix up reparse points--- mostly shared between UNIX and Windows */
+tchar *
+fixup_symlink(tchar *dest, u64 capture_root_ino, u64 capture_root_dev)
+{
+       tchar *p = dest;
+
+#ifdef __WIN32__
+       /* Skip over drive letter */
+       if (*p != RP_PATH_SEPARATOR)
+               p += 2;
+#endif
+
+       DEBUG("Fixing symlink or junction \"%"TS"\"", dest);
+       for (;;) {
+               tchar save;
+               int ret;
+               u64 ino;
+               u64 dev;
+
+               while (*p == RP_PATH_SEPARATOR)
+                       p++;
+
+               save = *p;
+               *p = T('\0');
+               ret = os_get_ino_and_dev(dest, &ino, &dev);
+               *p = save;
+
+               if (ino == capture_root_ino && dev == capture_root_dev) {
+                       /* Link points inside capture root.  Return abbreviated
+                        * path. */
+                       if (*p == T('\0'))
+                               *(p - 1) = RP_PATH_SEPARATOR;
+                       while (p - 1 >= dest && *(p - 1) == RP_PATH_SEPARATOR)
+                               p--;
+               #ifdef __WIN32__
+                       /* Add back drive letter */
+                       if (*dest != RP_PATH_SEPARATOR) {
+                               *--p = *(dest + 1);
+                               *--p = *dest;
+                       }
+               #endif
+                       wimlib_assert(p >= dest);
+                       return p;
+               }
+
+               if (*p == T('\0')) {
+                       /* Link points outside capture root. */
+                       return NULL;
+               }
+
+               do {
+                       p++;
+               } while (*p != RP_PATH_SEPARATOR && *p != T('\0'));
+       }
+}
+
index 1d3edcd7cc3f43cf1c03cdf56b03b929812a9fef..bde430f1662162266112019dcd8e72ed320a812f 100644 (file)
@@ -671,6 +671,8 @@ inode_set_symlink(struct wim_inode *inode, const char *target,
                  struct wim_lookup_table *lookup_table,
                  struct wim_lookup_table_entry **lte_ret);
 #endif
                  struct wim_lookup_table *lookup_table,
                  struct wim_lookup_table_entry **lte_ret);
 #endif
+extern tchar *
+fixup_symlink(tchar *dest, u64 capture_root_ino, u64 capture_root_dev);
 
 /* verify.c */
 
 
 /* verify.c */
 
index 774222497627560bb8bb08a13023d60ac92552e3..b10a4058ab05d2fb654bcbdff72260590d6f52a8 100644 (file)
@@ -39,6 +39,7 @@
 #include "lookup_table.h"
 #include "security.h"
 #include "endianness.h"
 #include "lookup_table.h"
 #include "security.h"
 #include "endianness.h"
+#include "buffer_io.h"
 #include <pthread.h>
 
 #include <errno.h>
 #include <pthread.h>
 
 #include <errno.h>
@@ -493,12 +494,7 @@ static int
 win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                  wchar_t *path,
                                  size_t path_num_chars,
 win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                  wchar_t *path,
                                  size_t path_num_chars,
-                                 struct wim_lookup_table *lookup_table,
-                                 struct wim_inode_table *inode_table,
-                                 struct sd_set *sd_set,
-                                 const struct wimlib_capture_config *config,
-                                 int add_image_flags,
-                                 wimlib_progress_func_t progress_func,
+                                 struct add_image_params *params,
                                  struct win32_capture_state *state,
                                  unsigned vol_flags);
 
                                  struct win32_capture_state *state,
                                  unsigned vol_flags);
 
@@ -508,12 +504,7 @@ static int
 win32_recurse_directory(struct wim_dentry *root,
                        wchar_t *dir_path,
                        size_t dir_path_num_chars,
 win32_recurse_directory(struct wim_dentry *root,
                        wchar_t *dir_path,
                        size_t dir_path_num_chars,
-                       struct wim_lookup_table *lookup_table,
-                       struct wim_inode_table *inode_table,
-                       struct sd_set *sd_set,
-                       const struct wimlib_capture_config *config,
-                       int add_image_flags,
-                       wimlib_progress_func_t progress_func,
+                       struct add_image_params *params,
                        struct win32_capture_state *state,
                        unsigned vol_flags)
 {
                        struct win32_capture_state *state,
                        unsigned vol_flags)
 {
@@ -564,12 +555,7 @@ win32_recurse_directory(struct wim_dentry *root,
                ret = win32_build_dentry_tree_recursive(&child,
                                                        dir_path,
                                                        path_len,
                ret = win32_build_dentry_tree_recursive(&child,
                                                        dir_path,
                                                        path_len,
-                                                       lookup_table,
-                                                       inode_table,
-                                                       sd_set,
-                                                       config,
-                                                       add_image_flags,
-                                                       progress_func,
+                                                       params,
                                                        state,
                                                        vol_flags);
                dir_path[dir_path_num_chars] = L'\0';
                                                        state,
                                                        vol_flags);
                dir_path[dir_path_num_chars] = L'\0';
@@ -590,6 +576,171 @@ out_find_close:
        return ret;
 }
 
        return ret;
 }
 
+int
+win32_get_file_and_vol_ids(const wchar_t *path, u64 *ino_ret, u64 *dev_ret)
+{
+       HANDLE hFile;
+       DWORD err;
+       BY_HANDLE_FILE_INFORMATION file_info;
+       int ret;
+
+       hFile = win32_open_existing_file(path, FILE_READ_ATTRIBUTES);
+       if (hFile == INVALID_HANDLE_VALUE) {
+               err = GetLastError();
+               WARNING("Failed to open \"%ls\" to get file and volume IDs",
+                       path);
+               win32_error(err);
+               return WIMLIB_ERR_OPEN;
+       }
+
+       if (!GetFileInformationByHandle(hFile, &file_info)) {
+               err = GetLastError();
+               ERROR("Failed to get file information for \"%ls\"", path);
+               win32_error(err);
+               ret = WIMLIB_ERR_STAT;
+       } else {
+               *ino_ret = ((u64)file_info.nFileIndexHigh << 32) |
+                           (u64)file_info.nFileIndexLow;
+               *dev_ret = file_info.dwVolumeSerialNumber;
+               ret = 0;
+       }
+       CloseHandle(hFile);
+       return ret;
+}
+
+enum rp_status {
+       RP_EXCLUDED       = 0x0,
+       RP_NOT_FIXED      = 0x1,
+       RP_FIXED_FULLPATH = 0x2,
+       RP_FIXED_ABSPATH  = 0x4,
+       RP_FIXED          = RP_FIXED_FULLPATH | RP_FIXED_ABSPATH,
+};
+
+static enum rp_status
+win32_maybe_rpfix_target(wchar_t *target, size_t *target_nchars_p,
+                        u64 capture_root_ino, u64 capture_root_dev)
+{
+       size_t target_nchars= *target_nchars_p;
+       size_t stripped_chars;
+       wchar_t *orig_target;
+
+       if (target_nchars == 0)
+               return RP_NOT_FIXED;
+
+       if (target[0] == L'\\') {
+               if (target_nchars >= 2 && target[1] == L'\\') {
+                       /* Probaby a volume.  Can't do anything with it. */
+                       DEBUG("Not fixing target (probably a volume)");
+                       return RP_NOT_FIXED;
+               } else if (target_nchars >= 7 &&
+                          target[1] == '?' &&
+                          target[2] == '?' &&
+                          target[3] == '\\' &&
+                          target[4] != '\0' &&
+                          target[5] == ':' &&
+                          target[6] == '\\')
+               {
+                       DEBUG("Full style path");
+                       /* Full \??\x:\ style path (may be junction or symlink)
+                        * */
+                       stripped_chars = 4;
+               } else {
+                       DEBUG("Absolute target without drive letter");
+                       /* Absolute target, without drive letter */
+                       stripped_chars = 0;
+               }
+       } else if (target_nchars >= 3 &&
+                  target[0] != L'\0' &&
+                  target[1] == L':' &&
+                  target[2] == L'\\')
+       {
+               DEBUG("Absolute target with drive letter");
+               /* Absolute target, with drive letter */
+               stripped_chars = 0;
+       } else {
+               DEBUG("Relative symlink or other link");
+               /* Relative symlink or other unexpected format */
+               return RP_NOT_FIXED;
+       }
+       target[target_nchars] = L'\0';
+       orig_target = target;
+       target = fixup_symlink(target + stripped_chars, capture_root_ino, capture_root_dev);
+       if (target) {
+               target_nchars = wcslen(target);
+               wmemmove(orig_target + stripped_chars, target, target_nchars + 1);
+               *target_nchars_p = target_nchars + stripped_chars;
+               DEBUG("Fixed reparse point (new target: \"%ls\")", orig_target);
+               return stripped_chars ? RP_FIXED_FULLPATH : RP_FIXED_ABSPATH;
+       } else {
+               return RP_EXCLUDED;
+       }
+}
+
+static enum rp_status
+win32_do_capture_rpfix(char *rpbuf, DWORD *rpbuflen_p,
+                      u64 capture_root_ino, u64 capture_root_dev)
+{
+       const char *p_get;
+       char *p_put;
+       u16 substitute_name_offset;
+       u16 substitute_name_len;
+       wchar_t *target;
+       size_t target_nchars;
+       enum rp_status status;
+       u32 rptag;
+       DWORD rpbuflen = *rpbuflen_p;
+
+       if (rpbuflen < 16)
+               return RP_EXCLUDED;
+       p_get = get_u32(rpbuf, &rptag);
+       p_get += 4;
+       p_get = get_u16(p_get, &substitute_name_offset);
+       p_get = get_u16(p_get, &substitute_name_len);
+       p_get += 4;
+       if ((size_t)substitute_name_offset + substitute_name_len > rpbuflen)
+               return RP_EXCLUDED;
+       if (rptag == WIM_IO_REPARSE_TAG_SYMLINK) {
+               if (rpbuflen < 20)
+                       return RP_EXCLUDED;
+               p_get += 4;
+       }
+
+
+       target = (wchar_t*)&p_get[substitute_name_offset];
+       target_nchars = substitute_name_len / 2;
+       /* Note: target is not necessarily null-terminated */
+
+       status = win32_maybe_rpfix_target(target, &target_nchars,
+                                         capture_root_ino, capture_root_dev);
+       if (status & RP_FIXED) {
+               size_t target_nbytes = target_nchars * 2;
+               size_t print_nbytes = target_nbytes;
+               wchar_t target_copy[target_nchars];
+               wchar_t *print_name = target_copy;
+
+               if (status == RP_FIXED_FULLPATH) {
+                       print_nbytes -= 8;
+                       print_name += 4;
+               }
+               wmemcpy(target_copy, target, target_nchars);
+               p_put = rpbuf + 8;
+               p_put = put_u16(p_put, 0); /* Substitute name offset */
+               p_put = put_u16(p_put, target_nbytes); /* Substitute name length */
+               p_put = put_u16(p_put, target_nbytes + 2); /* Print name offset */
+               p_put = put_u16(p_put, print_nbytes); /* Print name length */
+               if (rptag == WIM_IO_REPARSE_TAG_SYMLINK)
+                       p_put = put_u32(p_put, 1);
+               p_put = put_bytes(p_put, target_nbytes, target_copy);
+               p_put = put_u16(p_put, 0);
+               p_put = put_bytes(p_put, print_nbytes, print_name);
+               p_put = put_u16(p_put, 0);
+               rpbuflen = p_put - rpbuf;
+               put_u16(rpbuf + 4, rpbuflen - 8);
+               *rpbuflen_p = rpbuflen;
+       }
+       return status;
+}
+
 /* Load a reparse point into a WIM inode.  It is just stored in memory.
  *
  * @hFile:  Open handle to a reparse point, with permission to read the reparse
 /* Load a reparse point into a WIM inode.  It is just stored in memory.
  *
  * @hFile:  Open handle to a reparse point, with permission to read the reparse
@@ -605,10 +756,11 @@ out_find_close:
  *
  * Returns 0 on success; nonzero on failure. */
 static int
  *
  * Returns 0 on success; nonzero on failure. */
 static int
-win32_capture_reparse_point(HANDLE hFile,
+win32_capture_reparse_point(struct wim_dentry **root_p,
+                           HANDLE hFile,
                            struct wim_inode *inode,
                            struct wim_inode *inode,
-                           struct wim_lookup_table *lookup_table,
-                           const wchar_t *path)
+                           const wchar_t *path,
+                           struct add_image_params *params)
 {
        DEBUG("Capturing reparse point \"%ls\"", path);
 
 {
        DEBUG("Capturing reparse point \"%ls\"", path);
 
@@ -616,6 +768,8 @@ win32_capture_reparse_point(HANDLE hFile,
         * cannot exceed 16 kilobytes." - MSDN  */
        char reparse_point_buf[REPARSE_POINT_MAX_SIZE];
        DWORD bytesReturned;
         * cannot exceed 16 kilobytes." - MSDN  */
        char reparse_point_buf[REPARSE_POINT_MAX_SIZE];
        DWORD bytesReturned;
+       char *fixed_buf;
+       DWORD fixed_len;
 
        if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT,
                             NULL, /* "Not used with this operation; set to NULL" */
 
        if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT,
                             NULL, /* "Not used with this operation; set to NULL" */
@@ -637,9 +791,26 @@ win32_capture_reparse_point(HANDLE hFile,
                return WIMLIB_ERR_READ;
        }
        inode->i_reparse_tag = le32_to_cpu(*(u32*)reparse_point_buf);
                return WIMLIB_ERR_READ;
        }
        inode->i_reparse_tag = le32_to_cpu(*(u32*)reparse_point_buf);
-       return inode_add_ads_with_data(inode, L"",
-                                      reparse_point_buf + 8,
-                                      bytesReturned - 8, lookup_table);
+
+       if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX &&
+           (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
+            inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
+       {
+               enum rp_status status;
+               status = win32_do_capture_rpfix(reparse_point_buf,
+                                               &bytesReturned,
+                                               params->capture_root_ino,
+                                               params->capture_root_dev);
+               if (status == RP_EXCLUDED) {
+                       free_dentry(*root_p);
+                       *root_p = NULL;
+                       return 0;
+               } else if (status & RP_FIXED) {
+                       inode->i_not_rpfixed = 0;
+               }
+       }
+       return inode_add_ads_with_data(inode, L"", reparse_point_buf + 8,
+                                      bytesReturned - 8, params->lookup_table);
 }
 
 /* Scans an unnamed or named stream of a Win32 file (not a reparse point
 }
 
 /* Scans an unnamed or named stream of a Win32 file (not a reparse point
@@ -884,12 +1055,7 @@ static int
 win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                  wchar_t *path,
                                  size_t path_num_chars,
 win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                  wchar_t *path,
                                  size_t path_num_chars,
-                                 struct wim_lookup_table *lookup_table,
-                                 struct wim_inode_table *inode_table,
-                                 struct sd_set *sd_set,
-                                 const struct wimlib_capture_config *config,
-                                 int add_image_flags,
-                                 wimlib_progress_func_t progress_func,
+                                 struct add_image_params *params,
                                  struct win32_capture_state *state,
                                  unsigned vol_flags)
 {
                                  struct win32_capture_state *state,
                                  unsigned vol_flags)
 {
@@ -899,30 +1065,30 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        u64 file_size;
        int ret = 0;
 
        u64 file_size;
        int ret = 0;
 
-       if (exclude_path(path, path_num_chars, config, true)) {
-               if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
+       if (exclude_path(path, path_num_chars, params->config, true)) {
+               if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
                        ERROR("Cannot exclude the root directory from capture");
                        ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
                        goto out;
                }
                        ERROR("Cannot exclude the root directory from capture");
                        ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
                        goto out;
                }
-               if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
-                   && progress_func)
+               if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
+                   && params->progress_func)
                {
                        union wimlib_progress_info info;
                        info.scan.cur_path = path;
                        info.scan.excluded = true;
                {
                        union wimlib_progress_info info;
                        info.scan.cur_path = path;
                        info.scan.excluded = true;
-                       progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+                       params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
                }
                goto out;
        }
 
                }
                goto out;
        }
 
-       if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
-           && progress_func)
+       if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
+           && params->progress_func)
        {
                union wimlib_progress_info info;
                info.scan.cur_path = path;
                info.scan.excluded = false;
        {
                union wimlib_progress_info info;
                info.scan.cur_path = path;
                info.scan.excluded = false;
-               progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+               params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
        }
 
        HANDLE hFile = win32_open_existing_file(path,
        }
 
        HANDLE hFile = win32_open_existing_file(path,
@@ -946,7 +1112,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        }
 
        /* Create a WIM dentry with an associated inode, which may be shared */
        }
 
        /* Create a WIM dentry with an associated inode, which may be shared */
-       ret = inode_table_new_dentry(inode_table,
+       ret = inode_table_new_dentry(params->inode_table,
                                     path_basename_with_len(path, path_num_chars),
                                     ((u64)file_info.nFileIndexHigh << 32) |
                                         (u64)file_info.nFileIndexLow,
                                     path_basename_with_len(path, path_num_chars),
                                     ((u64)file_info.nFileIndexHigh << 32) |
                                         (u64)file_info.nFileIndexLow,
@@ -970,13 +1136,14 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime);
        inode->i_resolved = 1;
 
        inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime);
        inode->i_resolved = 1;
 
-       add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
+       params->add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
 
 
-       if (!(add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)
+       if (!(params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)
            && (vol_flags & FILE_PERSISTENT_ACLS))
        {
            && (vol_flags & FILE_PERSISTENT_ACLS))
        {
-               ret = win32_get_security_descriptor(root, sd_set, path, state,
-                                                   add_image_flags);
+               ret = win32_get_security_descriptor(root, params->sd_set,
+                                                   path, state,
+                                                   params->add_image_flags);
                if (ret)
                        goto out_close_handle;
        }
                if (ret)
                        goto out_close_handle;
        }
@@ -992,7 +1159,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                ret = win32_capture_streams(path,
                                            path_num_chars,
                                            inode,
                ret = win32_capture_streams(path,
                                            path_num_chars,
                                            inode,
-                                           lookup_table,
+                                           params->lookup_table,
                                            file_size,
                                            vol_flags);
                if (ret)
                                            file_size,
                                            vol_flags);
                if (ret)
@@ -1000,29 +1167,21 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                ret = win32_recurse_directory(root,
                                              path,
                                              path_num_chars,
                ret = win32_recurse_directory(root,
                                              path,
                                              path_num_chars,
-                                             lookup_table,
-                                             inode_table,
-                                             sd_set,
-                                             config,
-                                             add_image_flags,
-                                             progress_func,
+                                             params,
                                              state,
                                              vol_flags);
        } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
                /* Reparse point: save the reparse tag and data.  Alternate data
                 * streams are not captured, if it's even possible for a reparse
                 * point to have alternate data streams... */
                                              state,
                                              vol_flags);
        } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
                /* Reparse point: save the reparse tag and data.  Alternate data
                 * streams are not captured, if it's even possible for a reparse
                 * point to have alternate data streams... */
-               ret = win32_capture_reparse_point(hFile,
-                                                 inode,
-                                                 lookup_table,
-                                                 path);
+               ret = win32_capture_reparse_point(&root, hFile, inode, path, params);
        } else {
                /* Not a directory, not a reparse point; capture the default
                 * file contents and any alternate data streams. */
                ret = win32_capture_streams(path,
                                            path_num_chars,
                                            inode,
        } else {
                /* Not a directory, not a reparse point; capture the default
                 * file contents and any alternate data streams. */
                ret = win32_capture_streams(path,
                                            path_num_chars,
                                            inode,
-                                           lookup_table,
+                                           params->lookup_table,
                                            file_size,
                                            vol_flags);
        }
                                            file_size,
                                            vol_flags);
        }
@@ -1032,7 +1191,7 @@ out:
        if (ret == 0)
                *root_ret = root;
        else
        if (ret == 0)
                *root_ret = root;
        else
-               free_dentry_tree(root, lookup_table);
+               free_dentry_tree(root, params->lookup_table);
        return ret;
 }
 
        return ret;
 }
 
@@ -1072,13 +1231,7 @@ win32_do_capture_warnings(const struct win32_capture_state *state,
 int
 win32_build_dentry_tree(struct wim_dentry **root_ret,
                        const wchar_t *root_disk_path,
 int
 win32_build_dentry_tree(struct wim_dentry **root_ret,
                        const wchar_t *root_disk_path,
-                       struct wim_lookup_table *lookup_table,
-                       struct wim_inode_table *inode_table,
-                       struct sd_set *sd_set,
-                       const struct wimlib_capture_config *config,
-                       int add_image_flags,
-                       wimlib_progress_func_t progress_func,
-                       void *extra_arg)
+                       struct add_image_params *params)
 {
        size_t path_nchars;
        wchar_t *path;
 {
        size_t path_nchars;
        wchar_t *path;
@@ -1086,10 +1239,17 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        struct win32_capture_state state;
        unsigned vol_flags;
 
        struct win32_capture_state state;
        unsigned vol_flags;
 
+
        path_nchars = wcslen(root_disk_path);
        if (path_nchars > 32767)
                return WIMLIB_ERR_INVALID_PARAM;
 
        path_nchars = wcslen(root_disk_path);
        if (path_nchars > 32767)
                return WIMLIB_ERR_INVALID_PARAM;
 
+       ret = win32_get_file_and_vol_ids(root_disk_path,
+                                        &params->capture_root_ino,
+                                        &params->capture_root_dev);
+       if (ret)
+               return ret;
+
        win32_get_vol_flags(root_disk_path, &vol_flags);
 
        /* There is no check for overflow later when this buffer is being used!
        win32_get_vol_flags(root_disk_path, &vol_flags);
 
        /* There is no check for overflow later when this buffer is being used!
@@ -1103,20 +1263,12 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        wmemcpy(path, root_disk_path, path_nchars + 1);
 
        memset(&state, 0, sizeof(state));
        wmemcpy(path, root_disk_path, path_nchars + 1);
 
        memset(&state, 0, sizeof(state));
-       ret = win32_build_dentry_tree_recursive(root_ret,
-                                               path,
-                                               path_nchars,
-                                               lookup_table,
-                                               inode_table,
-                                               sd_set,
-                                               config,
-                                               add_image_flags,
-                                               progress_func,
-                                               &state,
-                                               vol_flags);
+       ret = win32_build_dentry_tree_recursive(root_ret, path,
+                                               path_nchars, params,
+                                               &state, vol_flags);
        FREE(path);
        if (ret == 0)
        FREE(path);
        if (ret == 0)
-               win32_do_capture_warnings(&state, add_image_flags);
+               win32_do_capture_warnings(&state, params->add_image_flags);
        return ret;
 }
 
        return ret;
 }
 
index b4d523614ec279d2556b03e827d7692395aae4d4..e525ccb4fda35d87a5f46b93133994fdea491cb2 100644 (file)
@@ -8,13 +8,10 @@
 extern int
 win32_build_dentry_tree(struct wim_dentry **root_ret,
                        const tchar *root_disk_path,
 extern int
 win32_build_dentry_tree(struct wim_dentry **root_ret,
                        const tchar *root_disk_path,
-                       struct wim_lookup_table *lookup_table,
-                       struct wim_inode_table *inode_table,
-                       struct sd_set *sd,
-                       const struct wimlib_capture_config *config,
-                       int add_image_flags,
-                       wimlib_progress_func_t progress_func,
-                       void *extra_arg);
+                       struct add_image_params *params);
+
+extern int
+win32_get_file_and_vol_ids(const wchar_t *path, u64 *ino_ret, u64 *dev_ret);
 
 extern int
 win32_read_file(const tchar *filename, HANDLE handle,
 
 extern int
 win32_read_file(const tchar *filename, HANDLE handle,