rpfix capture on UNIX
authorEric Biggers <ebiggers3@gmail.com>
Mon, 22 Apr 2013 01:41:10 +0000 (20:41 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 22 Apr 2013 01:41:10 +0000 (20:41 -0500)
programs/imagex.c
src/add_image.c
src/ntfs-capture.c
src/wimlib.h
src/wimlib_internal.h
tests/test-imagex-capture_and_apply

index c74bdb2..afaf110 100644 (file)
@@ -89,6 +89,7 @@ IMAGEX_PROGNAME" append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
 "                     [--verbose] [--dereference] [--config=FILE]\n"
 "                     [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n"
 "                     [--source-list] [--no-acls] [--strict-acls]\n"
+"                     [--rpfix] [--norpfix]\n"
 ),
 [APPLY] =
 T(
@@ -104,6 +105,7 @@ IMAGEX_PROGNAME" capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
 "                      [--flags EDITION_ID] [--verbose] [--dereference]\n"
 "                      [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n"
 "                      [--source-list] [--no-acls] [--strict-acls]\n"
+"                      [--rpfix] [--norpfix]\n"
 ),
 [DELETE] =
 T(
@@ -173,9 +175,11 @@ enum {
        IMAGEX_LOOKUP_TABLE_OPTION,
        IMAGEX_METADATA_OPTION,
        IMAGEX_NO_ACLS_OPTION,
+       IMAGEX_NORPFIX_OPTION,
        IMAGEX_REBULID_OPTION,
        IMAGEX_RECOMPRESS_OPTION,
        IMAGEX_REF_OPTION,
+       IMAGEX_RPFIX_OPTION,
        IMAGEX_SOFT_OPTION,
        IMAGEX_SOURCE_LIST_OPTION,
        IMAGEX_STAGING_DIR_OPTION,
@@ -215,6 +219,8 @@ static const struct option capture_or_append_options[] = {
        {T("noacls"),      no_argument,       NULL, IMAGEX_NO_ACLS_OPTION},
        {T("no-acls"),     no_argument,       NULL, IMAGEX_NO_ACLS_OPTION},
        {T("strict-acls"), no_argument,       NULL, IMAGEX_STRICT_ACLS_OPTION},
+       {T("rpfix"),       no_argument,       NULL, IMAGEX_RPFIX_OPTION},
+       {T("norpfix"),     no_argument,       NULL, IMAGEX_NORPFIX_OPTION},
        {NULL, 0, NULL, 0},
 };
 static const struct option delete_options[] = {
@@ -1344,6 +1350,12 @@ imagex_capture_or_append(int argc, tchar **argv)
                case IMAGEX_STRICT_ACLS_OPTION:
                        add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_STRICT_ACLS;
                        break;
+               case IMAGEX_RPFIX_OPTION:
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+                       break;
+               case IMAGEX_NORPFIX_OPTION:
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NORPFIX;
+                       break;
                default:
                        usage(cmd);
                        return -1;
index 7a0ef11..e45bc1c 100644 (file)
@@ -123,21 +123,13 @@ static int
 unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                 char *path,
                                 size_t path_len,
-                                struct wim_lookup_table *lookup_table,
-                                struct wim_inode_table *inode_table,
-                                const struct wimlib_capture_config *config,
-                                int add_image_flags,
-                                wimlib_progress_func_t progress_func);
+                                struct add_image_params *params);
 
 static int
 unix_capture_directory(struct wim_dentry *dir_dentry,
                       char *path,
                       size_t path_len,
-                      struct wim_lookup_table *lookup_table,
-                      struct wim_inode_table *inode_table,
-                      const struct wimlib_capture_config *config,
-                      int add_image_flags,
-                      wimlib_progress_func_t progress_func)
+                      struct add_image_params *params)
 {
 
        DIR *dir;
@@ -177,11 +169,7 @@ unix_capture_directory(struct wim_dentry *dir_dentry,
                ret = unix_build_dentry_tree_recursive(&child,
                                                       path,
                                                       path_len + 1 + name_len,
-                                                      lookup_table,
-                                                      inode_table,
-                                                      config,
-                                                      add_image_flags,
-                                                      progress_func);
+                                                      params);
                if (ret)
                        break;
                if (child)
@@ -191,10 +179,58 @@ unix_capture_directory(struct wim_dentry *dir_dentry,
        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(const char *path,
+unix_capture_symlink(struct wim_dentry **root_p,
+                    const char *path,
                     struct wim_inode *inode,
-                    struct wim_lookup_table *lookup_table)
+                    struct add_image_params *params)
 {
        char deref_name_buf[4096];
        ssize_t deref_name_len;
@@ -212,10 +248,30 @@ unix_capture_symlink(const char *path,
        deref_name_len = readlink(path, deref_name_buf,
                                  sizeof(deref_name_buf) - 1);
        if (deref_name_len >= 0) {
-               deref_name_buf[deref_name_len] = '\0';
-               DEBUG("Read symlink `%s'", deref_name_buf);
-               ret = inode_set_symlink(inode, deref_name_buf,
-                                       lookup_table, NULL);
+               char *dest = deref_name_buf;
+
+               dest[deref_name_len] = '\0';
+               DEBUG("Read symlink `%s'", dest);
+
+               if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX) &&
+                    dest[0] == '/')
+               {
+                       dest = fixup_symlink(dest,
+                                            params->capture_root_ino,
+                                            params->capture_root_dev);
+                       if (!dest) {
+                               WARNING("Ignoring out of tree absolute symlink "
+                                       "\"%s\" -> \"%s\"\n"
+                                       "          (Use --norpfix to capture "
+                                       "absolute symlinks as-is)",
+                                       path, deref_name_buf);
+                               free_dentry(*root_p);
+                               *root_p = NULL;
+                               return 0;
+                       }
+               }
+               ret = inode_set_symlink(inode, dest,
+                                       params->lookup_table, NULL);
                if (ret == 0) {
                        /* Unfortunately, Windows seems to have the concept of
                         * "file" symbolic links as being different from
@@ -239,46 +295,42 @@ static int
 unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                 char *path,
                                 size_t path_len,
-                                struct wim_lookup_table *lookup_table,
-                                struct wim_inode_table *inode_table,
-                                const struct wimlib_capture_config *config,
-                                int add_image_flags,
-                                wimlib_progress_func_t progress_func)
+                                struct add_image_params *params)
 {
        struct wim_dentry *root = NULL;
        int ret = 0;
        struct wim_inode *inode;
 
-       if (exclude_path(path, path_len, config, true)) {
-               if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
+       if (exclude_path(path, path_len, 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;
                }
-               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;
-                       progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+                       params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
                }
                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;
-               progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+               params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
        }
 
-       /* UNIX version of capturing a directory tree */
        struct stat stbuf;
        int (*stat_fn)(const char *restrict, struct stat *restrict);
-       if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)
+       if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) ||
+           (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT))
                stat_fn = stat;
        else
                stat_fn = lstat;
@@ -288,25 +340,6 @@ unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                ERROR_WITH_ERRNO("Failed to stat `%s'", path);
                goto out;
        }
-
-       if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
-             !S_ISDIR(stbuf.st_mode))
-       {
-               /* Do a dereference-stat in case the root is a symbolic link.
-                * This case is allowed, provided that the symbolic link points
-                * to a directory. */
-               ret = stat(path, &stbuf);
-               if (ret != 0) {
-                       ERROR_WITH_ERRNO("Failed to stat `%s'", path);
-                       ret = WIMLIB_ERR_STAT;
-                       goto out;
-               }
-               if (!S_ISDIR(stbuf.st_mode)) {
-                       ERROR("`%s' is not a directory", path);
-                       ret = WIMLIB_ERR_NOTDIR;
-                       goto out;
-               }
-       }
        if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)
            && !S_ISLNK(stbuf.st_mode)) {
                ERROR("`%s' is not a regular file, directory, or symbolic link.",
@@ -315,7 +348,7 @@ unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                goto out;
        }
 
-       ret = inode_table_new_dentry(inode_table,
+       ret = inode_table_new_dentry(params->inode_table,
                                     path_basename_with_len(path, path_len),
                                     stbuf.st_ino,
                                     stbuf.st_dev,
@@ -338,30 +371,29 @@ unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        inode->i_last_access_time = unix_timestamp_to_wim(stbuf.st_atime);
 #endif
        inode->i_resolved = 1;
-       if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
+       if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
                ret = inode_set_unix_data(inode, stbuf.st_uid,
                                          stbuf.st_gid,
                                          stbuf.st_mode,
-                                         lookup_table,
+                                         params->lookup_table,
                                          UNIX_DATA_ALL | UNIX_DATA_CREATE);
                if (ret)
                        goto out;
        }
-       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 (S_ISREG(stbuf.st_mode))
                ret = unix_capture_regular_file(path, stbuf.st_size,
-                                               inode, lookup_table);
+                                               inode, params->lookup_table);
        else if (S_ISDIR(stbuf.st_mode))
-               ret = unix_capture_directory(root, path, path_len,
-                                            lookup_table, inode_table, config,
-                                            add_image_flags, progress_func);
+               ret = unix_capture_directory(root, path, path_len, params);
        else
-               ret = unix_capture_symlink(path, inode, lookup_table);
+               ret = unix_capture_symlink(&root, path, inode, params);
 out:
        if (ret == 0)
                *root_ret = root;
        else
-               free_dentry_tree(root, lookup_table);
+               free_dentry_tree(root, params->lookup_table);
        return ret;
 }
 
@@ -376,20 +408,7 @@ out:
  *
  * @root_disk_path:  The path to the root of the directory tree on disk.
  *
- * @lookup_table: The lookup table for the WIM file.  For each file added to the
- *             dentry tree being built, an entry is added to the lookup table,
- *             unless an identical stream is already in the lookup table.
- *             These lookup table entries that are added point to the path of
- *             the file on disk.
- *
- * @sd_set:    Ignored.  (Security data only captured in NTFS mode.)
- *
- * @config:
- *             Configuration for files to be excluded from capture.
- *
- * @add_flags:  Bitwise or of WIMLIB_ADD_IMAGE_FLAG_*
- *
- * @extra_arg: Ignored
+ * @params:     See doc for `struct add_image_params'.
  *
  * @return:    0 on success, nonzero on failure.  It is a failure if any of
  *             the files cannot be `stat'ed, or if any of the needed
@@ -401,19 +420,29 @@ out:
 static int
 unix_build_dentry_tree(struct wim_dentry **root_ret,
                       const char *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)
 {
        char *path_buf;
        int ret;
        size_t path_len;
        size_t path_bufsz;
 
+       {
+               struct stat root_stbuf;
+               if (stat(root_disk_path, &root_stbuf)) {
+                       ERROR_WITH_ERRNO("Failed to stat \"%s\"", root_disk_path);
+                       return WIMLIB_ERR_STAT;
+               }
+
+               if (!S_ISDIR(root_stbuf.st_mode)) {
+                       ERROR("Root of capture \"%s\" is not a directory",
+                             root_disk_path);
+                       return WIMLIB_ERR_NOTDIR;
+               }
+               params->capture_root_ino = root_stbuf.st_ino;
+               params->capture_root_dev = root_stbuf.st_dev;
+       }
+
        path_bufsz = min(32790, PATH_MAX + 1);
        path_len = strlen(root_disk_path);
 
@@ -424,14 +453,9 @@ unix_build_dentry_tree(struct wim_dentry **root_ret,
        if (!path_buf)
                return WIMLIB_ERR_NOMEM;
        memcpy(path_buf, root_disk_path, path_len + 1);
-       ret = unix_build_dentry_tree_recursive(root_ret,
-                                              path_buf,
-                                              path_len,
-                                              lookup_table,
-                                              inode_table,
-                                              config,
-                                              add_image_flags,
-                                              progress_func);
+
+       ret = unix_build_dentry_tree_recursive(root_ret, path_buf,
+                                              path_len, params);
        FREE(path_buf);
        return ret;
 }
@@ -821,13 +845,7 @@ wimlib_add_image_multisource(WIMStruct *w,
 {
        int (*capture_tree)(struct wim_dentry **,
                            const tchar *,
-                           struct wim_lookup_table *,
-                           struct wim_inode_table *,
-                           struct sd_set *,
-                           const struct wimlib_capture_config *,
-                           int,
-                           wimlib_progress_func_t,
-                           void *);
+                           struct add_image_params *);
        void *extra_arg;
        struct wim_dentry *root_dentry;
        struct wim_dentry *branch;
@@ -835,6 +853,7 @@ wimlib_add_image_multisource(WIMStruct *w,
        struct wim_image_metadata *imd;
        struct wim_inode_table inode_table;
        struct list_head unhashed_streams;
+       struct add_image_params params;
        int ret;
        struct sd_set sd_set;
 #ifdef WITH_NTFS_3G
@@ -882,6 +901,19 @@ wimlib_add_image_multisource(WIMStruct *w,
        if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
                add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE;
 
+       if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
+                               WIMLIB_ADD_IMAGE_FLAG_RPFIX)) ==
+               (WIMLIB_ADD_IMAGE_FLAG_RPFIX | WIMLIB_ADD_IMAGE_FLAG_NORPFIX))
+       {
+               ERROR("Cannot specify RPFIX and NORPFIX flags at the same time!");
+               return WIMLIB_ERR_INVALID_PARAM;
+       }
+
+       if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
+                               WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == 0)
+               if (w->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+
        if (!name || !*name) {
                ERROR("Must specify a non-empty string for the image name");
                return WIMLIB_ERR_INVALID_PARAM;
@@ -936,6 +968,14 @@ wimlib_add_image_multisource(WIMStruct *w,
        INIT_LIST_HEAD(&unhashed_streams);
        w->lookup_table->unhashed_streams = &unhashed_streams;
        root_dentry = NULL;
+
+       params.lookup_table = w->lookup_table;
+       params.inode_table = &inode_table;
+       params.sd_set = &sd_set;
+       params.config = config;
+       params.add_image_flags = add_image_flags;
+       params.progress_func = progress_func;
+       params.extra_arg = extra_arg;
        for (size_t i = 0; i < num_sources; i++) {
                int flags;
                union wimlib_progress_info progress;
@@ -955,14 +995,8 @@ wimlib_add_image_multisource(WIMStruct *w,
                flags = add_image_flags | WIMLIB_ADD_IMAGE_FLAG_SOURCE;
                if (!*sources[i].wim_target_path)
                        flags |= WIMLIB_ADD_IMAGE_FLAG_ROOT;
-               ret = (*capture_tree)(&branch,
-                                     sources[i].fs_source_path,
-                                     w->lookup_table,
-                                     &inode_table,
-                                     &sd_set,
-                                     config,
-                                     flags,
-                                     progress_func, extra_arg);
+               ret = (*capture_tree)(&branch, sources[i].fs_source_path,
+                                     &params);
                if (ret) {
                        ERROR("Failed to build dentry tree for `%"TS"'",
                              sources[i].fs_source_path);
@@ -1020,6 +1054,9 @@ wimlib_add_image_multisource(WIMStruct *w,
        if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
                wimlib_set_boot_idx(w, w->hdr.image_count);
 
+       if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX)
+               w->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
+
        ret = 0;
        goto out_destroy_inode_table;
 out_put_imd:
index f447468..3c90670 100644 (file)
@@ -441,14 +441,9 @@ struct readdir_ctx {
        ntfs_inode *dir_ni;
        char *path;
        size_t path_len;
-       struct wim_lookup_table *lookup_table;
-       struct wim_inode_table *inode_table;
-       struct sd_set *sd_set;
        struct dos_name_map *dos_name_map;
-       const struct wimlib_capture_config *config;
        ntfs_volume *vol;
-       int add_image_flags;
-       wimlib_progress_func_t progress_func;
+       struct add_image_params *params;
 };
 
 static int
@@ -458,13 +453,8 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p,
                                 char *path,
                                 size_t path_len,
                                 int name_type,
-                                struct wim_lookup_table *lookup_table,
-                                struct wim_inode_table *inode_table,
-                                struct sd_set *sd_set,
-                                const struct wimlib_capture_config *config,
                                 ntfs_volume *ntfs_vol,
-                                int add_image_flags,
-                                wimlib_progress_func_t progress_func);
+                                struct add_image_params *params);
 
 static int
 wim_ntfs_capture_filldir(void *dirent, const ntfschar *name,
@@ -523,12 +513,7 @@ wim_ntfs_capture_filldir(void *dirent, const ntfschar *name,
        child = NULL;
        ret = build_dentry_tree_ntfs_recursive(&child, ctx->dir_ni,
                                               ni, ctx->path, path_len, name_type,
-                                              ctx->lookup_table,
-                                              ctx->inode_table,
-                                              ctx->sd_set,
-                                              ctx->config, ctx->vol,
-                                              ctx->add_image_flags,
-                                              ctx->progress_func);
+                                              ctx->vol, ctx->params);
        if (child)
                dentry_add_child(ctx->parent, child);
        ntfs_inode_close(ni);
@@ -549,13 +534,8 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
                                 char *path,
                                 size_t path_len,
                                 int name_type,
-                                struct wim_lookup_table *lookup_table,
-                                struct wim_inode_table *inode_table,
-                                struct sd_set *sd_set,
-                                const struct wimlib_capture_config *config,
                                 ntfs_volume *vol,
-                                int add_image_flags,
-                                wimlib_progress_func_t progress_func)
+                                struct add_image_params *params)
 {
        u32 attributes;
        int ret;
@@ -563,16 +543,16 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
        struct wim_inode *inode;
        ATTR_TYPES stream_type;
 
-       if (exclude_path(path, path_len, config, false)) {
+       if (exclude_path(path, path_len, params->config, false)) {
                /* Exclude a file or directory tree based on the capture
                 * configuration file */
-               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;
-                       progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+                       params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
                }
                root = NULL;
                ret = 0;
@@ -592,17 +572,17 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
                return WIMLIB_ERR_NTFS_3G;
        }
 
-       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;
-               progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+               params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
        }
 
        /* 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_len),
                                     ni->mft_no,
                                     0,
@@ -635,8 +615,8 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
         * - Directories: capture any named data streams
         * - Reparse points: capture reparse data only
         */
-       ret = capture_ntfs_streams(inode, ni, path, path_len, lookup_table,
-                                  vol, stream_type);
+       ret = capture_ntfs_streams(inode, ni, path, path_len,
+                                  params->lookup_table, vol, stream_type);
        if (ret)
                goto out;
 
@@ -650,14 +630,9 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
                        .dir_ni          = ni,
                        .path            = path,
                        .path_len        = path_len,
-                       .lookup_table    = lookup_table,
-                       .inode_table     = inode_table,
-                       .sd_set          = sd_set,
                        .dos_name_map    = &dos_name_map,
-                       .config          = config,
                        .vol             = vol,
-                       .add_image_flags = add_image_flags,
-                       .progress_func   = progress_func,
+                       .params          = params,
                };
                ret = ntfs_readdir(ni, &pos, &ctx, wim_ntfs_capture_filldir);
                if (ret) {
@@ -672,7 +647,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
                        goto out;
        }
 
-       if (!(add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)) {
+       if (!(params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)) {
                /* Get security descriptor */
                char _sd[1];
                char *sd = _sd;
@@ -686,7 +661,8 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret,
                                                         ni, dir_ni, sd, ret);
                }
                if (ret > 0) {
-                       inode->i_security_id = sd_set_add_sd(sd_set, sd, ret);
+                       inode->i_security_id = sd_set_add_sd(params->sd_set,
+                                                            sd, ret);
                        if (inode->i_security_id == -1) {
                                ERROR("Out of memory");
                                ret = WIMLIB_ERR_NOMEM;
@@ -708,7 +684,7 @@ out:
        if (ret == 0)
                *root_ret = root;
        else
-               free_dentry_tree(root, lookup_table);
+               free_dentry_tree(root, params->lookup_table);
        return ret;
 }
 
@@ -726,13 +702,7 @@ do_ntfs_umount(struct _ntfs_volume *vol)
 int
 build_dentry_tree_ntfs(struct wim_dentry **root_p,
                       const char *device,
-                      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)
 {
        ntfs_volume *vol;
        ntfs_inode *root_ni;
@@ -780,12 +750,7 @@ build_dentry_tree_ntfs(struct wim_dentry **root_p,
        path[0] = '/';
        path[1] = '\0';
        ret = build_dentry_tree_ntfs_recursive(root_p, NULL, root_ni, path, 1,
-                                              FILE_NAME_POSIX, lookup_table,
-                                              inode_table,
-                                              sd_set,
-                                              config, vol,
-                                              add_image_flags,
-                                              progress_func);
+                                              FILE_NAME_POSIX, vol, params);
 out_cleanup:
        FREE(path);
        ntfs_inode_close(root_ni);
@@ -804,7 +769,7 @@ out:
        } else {
                /* We need to leave the NTFS volume mounted so that we can read
                 * the NTFS files again when we are actually writing the WIM */
-               *(ntfs_volume**)extra_arg = vol;
+               *(ntfs_volume**)params->extra_arg = vol;
        }
        return ret;
 }
index f5aa9da..479fa24 100644 (file)
@@ -694,6 +694,19 @@ struct wimlib_capture_config {
  * ::WIMLIB_ADD_IMAGE_FLAG_VERBOSE. */
 #define WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE          0x00000080
 
+/** Reparse-point fixups:  Modify absolute symbolic links (or junction points,
+ * in the case of Windows) that point inside the directory being captured to
+ * instead be absolute relative to the directory being captured, rather than the
+ * current root.
+ *
+ * Without this flag, the default is to do the reparse-point fixups if
+ * WIM_HDR_FLAG_RP_FIX is set in the WIM header. */
+#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. */
+#define WIMLIB_ADD_IMAGE_FLAG_NORPFIX                  0x00000200
+
 /******************************
  * WIMLIB_EXPORT_FLAG_* *
  ******************************/
index 29c5ea6..1078457 100644 (file)
@@ -197,9 +197,11 @@ struct wim_header {
  * file (if supported by the underlying filesystem). */
 #define WIM_HDR_FLAG_WRITE_IN_PROGRESS  0x00000040
 
-/* Reparse point fixup ???
- * This has something to do with absolute targets of reparse points / symbolic
- * links but I don't know what.  wimlib ignores this flag.  */
+/* Reparse point fixup flag.  See docs for --rpfix and --norpfix in imagex, or
+ * WIMLIB_ADD_IMAGE_FLAG_{RPFIX,NORPFIX} in wimlib.h.  Note that
+ * WIM_HDR_FLAG_RP_FIX is a header flag and just sets the default behavior for
+ * the WIM; it can still be overridder on a per-image basis.  But there is no
+ * flag to set the default behavior for a specific image. */
 #define WIM_HDR_FLAG_RP_FIX             0x00000080
 
 /* Unused, reserved flag for another compression type */
@@ -398,20 +400,6 @@ zero_resource_entry(struct resource_entry *entry)
 
 /* add_image.c */
 
-extern bool
-exclude_path(const tchar *path, size_t path_len,
-            const struct wimlib_capture_config *config,
-            bool exclude_prefix);
-
-/* extract_image.c */
-
-/* Internal use only */
-#define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE                0x80000000
-#define WIMLIB_EXTRACT_FLAG_NO_STREAMS         0x40000000
-#define WIMLIB_EXTRACT_MASK_PUBLIC             0x3fffffff
-
-/* hardlink.c */
-
 /* Hash table to find inodes, given an inode number (in the case of reading
  * a WIM images), or both an inode number and a device number (in the case of
  * capturing a WIM image). */
@@ -435,6 +423,52 @@ struct wim_inode_table {
        struct list_head extra_inodes;
 };
 
+/* Common parameters to implementations of building an in-memory dentry tree
+ * from an on-disk directory structure. */
+struct add_image_params {
+       /* Pointer to the lookup table of the WIM. */
+       struct wim_lookup_table *lookup_table;
+
+       /* Pointer to a hash table of inodes that have been captured for this
+        * WIM image so far. */
+       struct wim_inode_table *inode_table;
+
+       /* Pointer to the set of security descriptors that have been captured
+        * for this image so far. */
+       struct sd_set *sd_set;
+
+       /* Pointer to the capture configuration, which indicates whether any
+        * files should be excluded from capture or not. */
+       const struct wimlib_capture_config *config;
+
+       /* Flags that affect the capture operation (WIMLIB_ADD_IMAGE_FLAG_*) */
+       int add_image_flags;
+
+       /* If non-NULL, the user-supplied progress function. */
+       wimlib_progress_func_t progress_func;
+
+       /* Extra argument; set to point to a pointer to the ntfs_volume for
+        * libntfs-3g capture.  */
+       void *extra_arg;
+
+       u64 capture_root_ino;
+       u64 capture_root_dev;
+};
+
+extern bool
+exclude_path(const tchar *path, size_t path_len,
+            const struct wimlib_capture_config *config,
+            bool exclude_prefix);
+
+/* extract_image.c */
+
+/* Internal use only */
+#define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE                0x80000000
+#define WIMLIB_EXTRACT_FLAG_NO_STREAMS         0x40000000
+#define WIMLIB_EXTRACT_MASK_PUBLIC             0x3fffffff
+
+/* hardlink.c */
+
 extern int
 init_inode_table(struct wim_inode_table *table, size_t capacity);
 
@@ -554,13 +588,7 @@ read_ntfs_file_prefix(const struct wim_lookup_table_entry *lte,
 extern int
 build_dentry_tree_ntfs(struct wim_dentry **root_p,
                       const tchar *device,
-                      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 *ctx);
 
 #ifdef WITH_NTFS_3G
 extern int
index e7b56e3..d457751 100755 (executable)
@@ -30,7 +30,7 @@ do_tree_cmp() {
 
 image_name=0
 do_test() {
-       for ctype in None LZX XPRESS; do
+       for ctype in None XPRESS LZX; do
 
                # Can we capture the WIM, apply it, and get the same result?
                cd in.dir
@@ -114,6 +114,35 @@ if [ -e out.dir/hiberfil.sys -o -e "out.dir/System Volume Information" ]; then
        error "Files were not excluded from capture as expected"
 fi
 
+__msg "Testing --rpfix"
+rm -r in.dir out.dir
+mkdir in.dir
+ln -s $PWD/in.dir          in.dir/absrootlink
+ln -s $PWD/in.dir////      in.dir/absrootlinkslashes
+ln -s /___NONEXISTENT___   in.dir/absnonexistent
+ln -s /usr/bin/env         in.dir/absoutoftree
+ln -s file                 in.dir/relalink
+ln -s $PWD/in.dir/file     in.dir/abslink
+ln -s $PWD/in.dir/file///  in.dir/abslinkslashes
+imagex capture --rpfix in.dir test.wim
+imagex apply --norpfix test.wim out.dir
+if [[ `readlink out.dir/absrootlink` != "/" ]] ||
+   [[ `readlink out.dir/absrootlinkslashes` != "////" ]]; then
+       error "imagex capture --rpfix failed to fix absolute link to capture root"
+fi
+
+if [[ -e out.dir/absnonexistent ]] ||
+   [[ -e out.dir/absoutoftree ]]; then
+       error "imagex capture --rpfix failed to exclude out of tree absolute links"
+fi
+if [[ `readlink out.dir/relalink` != "file" ]]; then
+       error "imagex capture --rpfix failed to capture relative symlink"
+fi
+if [[ `readlink out.dir/abslink` != "/file" ]] ||
+   [[ `readlink out.dir/abslinkslashes` != "/file///" ]]; then
+       error "imagex capture --rpfix did fix absolute link properly"
+fi
+
 echo "**********************************************************"
 echo "          imagex capture/apply tests passed               "
 echo "**********************************************************"