From aee5df8a6702da0782d64333eb8b3d1fb52c880b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 21 Apr 2013 20:41:10 -0500 Subject: [PATCH] rpfix capture on UNIX --- programs/imagex.c | 12 ++ src/add_image.c | 255 ++++++++++++++++------------ src/ntfs-capture.c | 79 +++------ src/wimlib.h | 13 ++ src/wimlib_internal.h | 76 ++++++--- tests/test-imagex-capture_and_apply | 31 +++- 6 files changed, 275 insertions(+), 191 deletions(-) diff --git a/programs/imagex.c b/programs/imagex.c index c74bdb25..afaf1102 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -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; diff --git a/src/add_image.c b/src/add_image.c index 7a0ef113..e45bc1c1 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -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, + ¶ms); 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: diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index f447468e..3c906707 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -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; } diff --git a/src/wimlib.h b/src/wimlib.h index f5aa9daa..479fa241 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -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_* * ******************************/ diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 29c5ea6b..10784571 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -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 diff --git a/tests/test-imagex-capture_and_apply b/tests/test-imagex-capture_and_apply index e7b56e35..d4577517 100755 --- a/tests/test-imagex-capture_and_apply +++ b/tests/test-imagex-capture_and_apply @@ -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 "**********************************************************" -- 2.43.0